diff --git a/application/config/simpletester.php b/application/config/simpletester.php new file mode 100644 index 00000000000..582cbf878dc --- /dev/null +++ b/application/config/simpletester.php @@ -0,0 +1,85 @@ +simpletester->Run(); +| +*/ +$config['noautorun'] = FALSE; + +/* +|-------------------------------------------------------------------------- +| Test files extension +|-------------------------------------------------------------------------- +| +| If your php files have a different extension, php5 for example, +| specify it here (without dot). All files ending with this extension will +| be added to the test suite. +| +*/ +$config['fileExtension'] = 'php'; + +/* +|-------------------------------------------------------------------------- +| Test title +|-------------------------------------------------------------------------- +| +| Here you can specify the title of the test suite. Will be displayed for +| example in the MinimalReporter when a test fails. +| +*/ +$config['testTitle'] = 'CodeIgnited Unit Tests'; diff --git a/application/controllers/survey.php b/application/controllers/survey.php index ee1854fe860..00205c2d9d9 100644 --- a/application/controllers/survey.php +++ b/application/controllers/survey.php @@ -16,924 +16,738 @@ class survey extends LSCI_Controller { - function __construct() - { - parent::__construct(); - } - - public function _remap($method, $params = array()) - { - array_unshift($params, $method); - return call_user_func_array(array($this, "action"), $params); - } - - function action() - { - global $surveyid, $thistpl, $totalquestions; - global $thissurvey, $thisstep; - global $clienttoken, $tokensexist, $token; - - //Replace $_GET: - $arg_list = func_get_args(); - if($arg_list[0]==__CLASS__) array_shift($arg_list); - if(count($arg_list)%2 == 0) { - for ($i = 0; $i < count($arg_list); $i+=2) { - //Sanitize input from URL with returnglobal - $param[$arg_list[$i]] = returnglobal($arg_list[$i], $arg_list[$i+1]); - } - } + function __construct() + { + parent::__construct(); + } - @ini_set('session.gc_maxlifetime', $this->config->item('sess_expiration')); - - //Load helpers, libraries and config vars - $this->load->helper("database"); - $this->load->helper("frontend"); - $this->load->helper("surveytranslator"); - - $relativeurl = $this->config->item("relativeurl"); - $defaultlang = $this->config->item("defaultlang"); - $siteadminname = $this->config->item("siteadminname"); - $siteadminemail = $this->config->item("siteadminemail"); - $sitename = $this->config->item("sitename"); - $standardtemplaterootdir = $this->config->item("standardtemplaterootdir"); - $dbprefix = $this->db->dbprefix; - - $this->load->library("Dtexts"); - - $_POST=$this->input->post(); - //$_SESSION=$this->session->userdata; - - $surveyid = isset($param['sid']) ? $param['sid'] : returnglobal('sid'); - $loadname= isset($param['loadname']) ? $param['loadname'] : returnglobal('loadname'); - $loadpass= isset($param['loadpass']) ? $param['loadpass'] : returnglobal('loadpass'); - $scid= isset($param['scid']) ? $param['scid'] : returnglobal('scid'); - $thisstep= isset($param['thisstep']) ? $param['thisstep'] : returnglobal('thisstep'); - $move = isset($param['move']) ? sanitize_paranoid_string($param['move']) : sanitize_paranoid_string(returnglobal('move')); - $clienttoken= isset($param['token']) ? sanitize_token($param['token']) : sanitize_token(returnglobal('token')); - - if(!isset($param['action'])) - $param['action'] = isset($_POST['action']) ? $_POST['action'] : null; - if(!isset($param['newtest'])) - $param['newtest'] = isset($_POST['newtest']) ? $_POST['newtest'] : null; - if(!isset($param['gid'])) - $param['gid'] = isset($_POST['gid']) ? $_POST['gid'] : null; - - if (!isset($thisstep)) - { - $thisstep = ""; - } + public function _remap($method, $params = array()) + { + array_unshift($params, $method); + return call_user_func_array(array($this, "action"), $params); + } - //This next line ensures that the $surveyid value is never anything but a number. - $surveyid=sanitize_int($surveyid); + function action() + { + global $surveyid, $thistpl, $totalquestions; + global $thissurvey, $thisstep; + global $clienttoken, $tokensexist, $token; - // Compute the Session name - // Session name is based: - // * on this specific limesurvey installation (Value SessionName in DB) - // * on the surveyid (from Get or Post param). If no surveyid is given we are on the public surveys portal + @ini_set('session.gc_maxlifetime', $this->config->item('sess_expiration')); - $sSessionname=getGlobalSetting('SessionName'); - if ($sSessionname!='') - { - if ($surveyid) - { - $sSessionname = $sSessionname.'-runtime-'.$surveyid; - } - else - { - $sSessionname = $sSessionname.'-runtime-publicportal'; - } - } - else - { - $sSessionname = "LimeSurveyRuntime-$surveyid"; - } + $this->_loadRequiredHelpersAndLibraries(); - // Establish / Switch to survey session - // Import data from current session (if available) to survey - // session if the survey session has no data. + $_POST = $this->input->post(); + //$_SESSION = $this->session->userdata; + $param = $this->_getParameters(func_get_args(), $_POST); - $__SESSION = array(); // session data copy store - $oSess = new LS_PHP_Session(); - if ($oSess->changeTo($sSessionname)) + $surveyid = $param['sid']; + $thisstep = $param['thisstep']; + $move = $param['move']; + $clienttoken = $param['token']; + $standardtemplaterootdir = $this->config->item("standardtemplaterootdir"); + + // unused vars in this method (used in methods using compacted method vars) + $loadname = $param['loadname']; + $loadpass = $param['loadpass']; + $sitename = $this->config->item("sitename"); + $relativeurl = $this->config->item("relativeurl"); + + $this->_setSessionToSurvey($surveyid); + + list($surveyExists, $isSurveyActive) = $this->_surveyExistsAndIsActive($surveyid); + + // collect all data in this method to pass on later + $redata = compact(array_keys(get_defined_vars())); + + if ( $this->_isClientTokenDifferentFromSessionToken($clienttoken) ) { - // Needed to call session_start() below. - $__SESSION =& $_SESSION; // reference current session data. - unset($_SESSION); - $_SESSION = array(); + $clang = $this->_loadLimesurveyLang($surveyid); + $asMessage = array( + $clang->gT('Token mismatch'), + $clang->gT("The token you provided doesn't match the one in your session."), + $clang->gT("Please wait to begin with a new session.") + ); + $this->_createNewUserSessionAndRedirect($surveyid, $redata, $asMessage); } - else + + if ( $this->_isSurveyFinished() ) { - session_name($sSessionname); + $clang = $this->_loadLimesurveyLang($surveyid); + $asMessage = array( + $clang->gT("Previous session is set to be finished."), + $clang->gT("Your browser reports that it was used previously to answer this survey. We are resetting the session so that you can start from the beginning."), + $clang->gT("Please wait to begin with a new session.") + ); + $this->_createNewUserSessionAndRedirect($surveyid, $redata, $asMessage); } - unset($oSess); - session_set_cookie_params(0,$relativeurl); - if (empty($_SESSION)) // the $_SESSION variable can be empty if register_globals is on + + if ($this->_isPreviewAction($param) && !$this->_canUserPreviewSurvey($surveyid)){ + $clang = $this->_loadLimesurveyLang($surveyid); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("We are sorry but you don't have permissions to do this.") + ); + $this->_killPage($redata, __LINE__); + } + + if ( $this->_surveyCantBeViewedWithCurrentPreviewAccess($surveyid, $isSurveyActive, $surveyExists) ) { - @session_start(); - if (empty($_SESSION)) // if this session is new, import old session + // admin session and permission have not already been imported + // for this particular survey + if ( !isset($_SESSION['USER_RIGHT_PREVIEW']) || $_SESSION['USER_RIGHT_PREVIEW'] != $surveyid) { - $_SESSION = $__SESSION; - unset($__SESSION); + // Store initial session name + $initial_session_name = session_name(); + + // One way (not implemented here) would be to start the + // user session from a duplicate of the admin session + // - destroy the new session + // - load admin session (with correct session name) + // - close admin session + // - change used session name to default + // - open new session (takes admin session id) + // - regenerate brand new session id for this session + + // The solution implemented here is to copy some + // fields from the admin session to the new session + // - first destroy the new (empty) user session + // - then open admin session + // - record interresting values from the admin session + // - duplicate admin session under another name and Id + // - destroy the duplicated admin session + // - start a brand new user session + // - copy interresting values in this user session + + @session_destroy(); // make it silent because for + // some strange reasons it fails sometimes + // which is not a problem + // but if it throws an error then future + // session functions won't work because + // headers are already sent. + if (isset($stg_SessionName) && $stg_SessionName) + { + @session_name($stg_SessionName); + } + else + { + session_name("LimeSurveyAdmin"); + } + session_start(); // Loads Admin Session + + $previewright=false; + $savesessionvars=Array(); + if (isset($_SESSION['loginID'])) + { + $rightquery="SELECT uid FROM ".($this->db->dbprefix('survey_permissions'))." WHERE sid=".$this->db->escape($surveyid)." AND uid = ".$this->db->escape($_SESSION['loginID'].' group by uid'); + $rightresult = db_execute_assoc($rightquery); //Checked + + // Currently it is enough to be listed in the survey + // user operator list to get preview access + if ($rightresult->num_rows() > 0 || $_SESSION['USER_RIGHT_SUPERADMIN'] == 1) + { + $previewright=true; + $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; + $savesessionvars["loginID"]=$_SESSION['loginID']; + $savesessionvars["user"]=$_SESSION['user']; + } + } + + // change session name and id + // then delete this new session + // ==> the original admin session remains valid + // ==> it is possible to start a new session + session_name($initial_session_name); + if ($sessionhandler=='db') + { + adodb_session_regenerate_id(); + } + elseif (session_regenerate_id() === false) + { + safe_die("Error Regenerating Session Id"); + } + @session_destroy(); + + // start new session + @session_start(); + // regenerate id so that the header geenrated by previous + // regenerate_id is overwritten + // needed after clearall + if ($sessionhandler=='db') + { + adodb_session_regenerate_id(); + } + elseif (session_regenerate_id() === false) + { + safe_die("Error Regenerating Session Id"); + } + + if ( $previewright === true) + { + foreach ($savesessionvars as $sesskey => $sessval) + { + $_SESSION[$sesskey]=$sessval; + } + } + } + else + { // already authorized + $previewright = true; } - $this->session->bind_userdata(); - } - // First check if survey is active - // if not: copy some vars from the admin session - // to a new user session + if ($previewright === false) + { + // print an error message + if (isset($_REQUEST['rootdir'])) + { + safe_die('You cannot start this script directly'); + } + $clang = $this->_loadLimesurveyLang($surveyid); + //A nice exit + sendcacheheaders(); + doHeader(); - if ($surveyid) - { - $issurveyactive=false; - $aRow=db_execute_assoc("SELECT * FROM ".$this->db->dbprefix('surveys')." WHERE sid=$surveyid")->row_array(); - if (isset($aRow['active'])) - { - $surveyexists=true; - if($aRow['active']=='Y') - { - $issurveyactive=true; - } - } - else - { - $surveyexists=false; - } - } + $redata = compact(array_keys(get_defined_vars())); + $this->_printTemplateContent($this->config->item("standardtemplaterootdir").'/default/startpage.pstpl', $redata, __LINE__); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("We are sorry but you don't have permissions to do this."), + sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']) + ); + + $this->_killPage($redata, __LINE__); + } + } - if ($clienttoken != '' && isset($_SESSION['token']) && - $clienttoken != $_SESSION['token']) - { - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - $clang = $this->limesurvey_lang; - // Let's first regenerate a session id - killSession(); - // Let's redirect the client to the same URL after having reseted the session - //header("Location: $rooturl/index.php?" .$_SERVER['QUERY_STRING']); - sendcacheheaders(); - doHeader(); - $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/startpage.pstpl"),array(),$redata,'survey[159]'); - echo "\t
\n" - ."\t

\n" - ."\t".$clang->gT("Token mismatch")."

\n" - ."\t".$clang->gT("The token you provided doesn't match the one in your session.")."

\n" - ."\t".$clang->gT("Please wait to begin with a new session.")."

\n" - ."\t

\n" - ."\t
\n"; - - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/endpage.pstpl"),array(),$redata,'survey[168]'); - doFooter(); - exit; - } + if (isset($_SESSION['srid'])) + { + $saved_id = $_SESSION['srid']; + } - if (isset($_SESSION['finished']) && $_SESSION['finished'] === true) - { - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - $clang = $this->limesurvey_lang; - // Let's first regenerate a session id - killSession(); - // Let's redirect the client to the same URL after having reseted the session - //header("Location: " .$this->config->site_url()."/".$this->uri->uri_string()); - sendcacheheaders(); - doHeader(); + if (!isset($_SESSION['s_lang']) && (isset($move)) ) + // geez ... a session time out! RUN! + { + if (isset($param['rootdir'])) + { + safe_die('You cannot start this script directly'); + } + $clang = $this->_loadLimesurveyLang($surveyid); + //A nice exit + sendcacheheaders(); + doHeader(); $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/startpage.pstpl"),array(),$redata,'survey[186]'); - echo "\t
\n" - ."\t

\n" - ."\t".$clang->gT("Previous session is set to be finished.")."

\n" - ."\t".$clang->gT("Your browser reports that it was used previously to answer this survey. We are resetting the session so that you can start from the beginning.")."

\n" - ."\t".$clang->gT("Please wait to begin with a new session.")."

\n" - ."\t

\n" - ."\t
\n"; - - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/endpage.pstpl"),array(),$redata,'survey[195]'); - doFooter(); - exit; - } - $previewgrp = false; - if (isset($param['action']) && ($param['action'] == 'previewgroup')){ - $rightquery="SELECT uid FROM {$dbprefix}survey_permissions WHERE sid=".$this->db->escape($surveyid)." AND uid = ".$this->db->escape($this->session->userdata('loginID')).' group by uid'; - $rightresult = db_execute_assoc($rightquery); - if ($rightresult->num_rows() > 0 || $this->session->userdata('USER_RIGHT_SUPERADMIN') == 1) - { - $previewgrp = true; - } - else - { - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - show_error("\t".$this->limesurvey_lang->gT("ERROR")."

\n" - ."\t".$this->limesurvey_lang->gT("We are sorry but you don't have permissions to do this.")."

\n"); - } - } + $this->_printTemplateContent($this->config->item("standardtemplaterootdir").'/default/startpage.pstpl', $redata, __LINE__); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("We are sorry but your session has expired."), + $clang->gT("Either you have been inactive for too long, you have cookies disabled for your browser, or there were problems with your connection."), + sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']) + ); + + $this->_killPage($redata, __LINE__); + }; + + // Set the language of the survey, either from POST, GET parameter of session var + if (isset($_POST['lang']) && $_POST['lang']!='') // this one comes from the language question + { + $templang = sanitize_languagecode($_POST['lang']); + $clang = SetSurveyLanguage( $surveyid, $templang); + UpdateSessionGroupList($surveyid, $templang); // to refresh the language strings in the group list session variable - if (($surveyid && - $issurveyactive===false && $surveyexists && - isset ($surveyPreview_require_Auth) && - $surveyPreview_require_Auth == true) && $previewgrp == false) - { - // admin session and permission have not already been imported - // for this particular survey - if ( !isset($_SESSION['USER_RIGHT_PREVIEW']) || - $_SESSION['USER_RIGHT_PREVIEW'] != $surveyid) - { - // Store initial session name - $initial_session_name=session_name(); - - // One way (not implemented here) would be to start the - // user session from a duplicate of the admin session - // - destroy the new session - // - load admin session (with correct session name) - // - close admin session - // - change used session name to default - // - open new session (takes admin session id) - // - regenerate brand new session id for this session - - // The solution implemented here is to copy some - // fields from the admin session to the new session - // - first destroy the new (empty) user session - // - then open admin session - // - record interresting values from the admin session - // - duplicate admin session under another name and Id - // - destroy the duplicated admin session - // - start a brand new user session - // - copy interresting values in this user session - - @session_destroy(); // make it silent because for - // some strange reasons it fails sometimes - // which is not a problem - // but if it throws an error then future - // session functions won't work because - // headers are already sent. - if (isset($stg_SessionName) && $stg_SessionName) - { - @session_name($stg_SessionName); - } - else - { - session_name("LimeSurveyAdmin"); - } - session_start(); // Loads Admin Session - - $previewright=false; - $savesessionvars=Array(); - if (isset($_SESSION['loginID'])) - { - $rightquery="SELECT uid FROM {$dbprefix}survey_permissions WHERE sid=".$this->db->escape($surveyid)." AND uid = ".$this->db->escape($_SESSION['loginID'].' group by uid'); - $rightresult = db_execute_assoc($rightquery); //Checked - - // Currently it is enough to be listed in the survey - // user operator list to get preview access - if ($rightresult->num_rows() > 0 || $_SESSION['USER_RIGHT_SUPERADMIN'] == 1) - { - $previewright=true; - $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; - $savesessionvars["loginID"]=$_SESSION['loginID']; - $savesessionvars["user"]=$_SESSION['user']; - } - } - - // change session name and id - // then delete this new session - // ==> the original admin session remains valid - // ==> it is possible to start a new session - session_name($initial_session_name); - if ($sessionhandler=='db') - { - adodb_session_regenerate_id(); - } - elseif (session_regenerate_id() === false) - { - safe_die("Error Regenerating Session Id"); - } - @session_destroy(); - - // start new session - @session_start(); - // regenerate id so that the header geenrated by previous - // regenerate_id is overwritten - // needed after clearall - if ($sessionhandler=='db') - { - adodb_session_regenerate_id(); - } - elseif (session_regenerate_id() === false) - { - safe_die("Error Regenerating Session Id"); - } - - if ( $previewright === true) - { - foreach ($savesessionvars as $sesskey => $sessval) - { - $_SESSION[$sesskey]=$sessval; - } - } - } - else - { // already authorized - $previewright = true; - } - - if ($previewright === false) - { - // print an error message - if (isset($_REQUEST['rootdir'])) - { - safe_die('You cannot start this script directly'); - } - //require_once(dirname(__FILE__).'/classes/core/language.php'); - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - $clang = $this->limesurvey_lang; - //A nice exit - sendcacheheaders(); - doHeader(); + UpdateFieldArray(); // to refresh question titles and question text + } + else if (isset($param['lang']) && $surveyid) + { + $templang = sanitize_languagecode($param['lang']); + $clang = SetSurveyLanguage( $surveyid, $templang); + UpdateSessionGroupList($surveyid, $templang); // to refresh the language strings in the group list session variable + UpdateFieldArray(); // to refresh question titles and question text + } - $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/startpage.pstpl"),array(),$redata,'survey[340]'); - echo "\t
\n" - ."\t

\n" - ."\t".$clang->gT("ERROR")."

\n" - ."\t".$clang->gT("We are sorry but you don't have permissions to do this.")."

\n" - ."\t".sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$siteadminname,encodeEmail($siteadminemail))."

\n" - ."\t

\n" - ."\t
\n"; - - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/endpage.pstpl"),array(),$redata,'survey[349]'); - doFooter(); - exit; - } - } - if (isset($_SESSION['srid'])) - { - $saved_id = $_SESSION['srid']; - } + if (isset($_SESSION['s_lang'])) + { + $clang = SetSurveyLanguage( $surveyid, $_SESSION['s_lang']); + } + elseif (isset($surveyid) && $surveyid) + { + $baselang = GetBaseLanguageFromSurveyID($surveyid); + $clang = SetSurveyLanguage( $surveyid, $baselang); + } + else + { + $baselang = $this->config->item("defaultlang"); + } - if (!isset($_SESSION['s_lang']) && (isset($move)) ) - // geez ... a session time out! RUN! - { - if (isset($param['rootdir'])) - { - safe_die('You cannot start this script directly'); - } - //require_once(dirname(__FILE__).'/classes/core/language.php'); - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - $clang = $this->limesurvey_lang; - //A nice exit - sendcacheheaders(); - doHeader(); + if (isset($param['embedded_inc'])) + { + safe_die('You cannot start this script directly'); + } - $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/startpage.pstpl"),array(),$redata,'survey[375]'); - echo "\t
\n" - ."\t

\n" - ."\t".$clang->gT("ERROR")."

\n" - ."\t".$clang->gT("We are sorry but your session has expired.")."

\n" - ."\t".$clang->gT("Either you have been inactive for too long, you have cookies disabled for your browser, or there were problems with your connection.")."

\n" - ."\t".sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$siteadminname,$siteadminemail)."

\n" - ."\t

\n" - ."\t
\n"; - - echo templatereplace(file_get_contents("$standardtemplaterootdir/default/endpage.pstpl"),array(),$redata,'survey[385]'); - doFooter(); - exit; - }; - - // Set the language of the survey, either from POST, GET parameter of session var - if (isset($_POST['lang']) && $_POST['lang']!='') // this one comes from the language question - { - $templang = sanitize_languagecode($_POST['lang']); - $clang = SetSurveyLanguage( $surveyid, $templang); - UpdateSessionGroupList($surveyid, $templang); // to refresh the language strings in the group list session variable - UpdateFieldArray(); // to refresh question titles and question text - } - else - if (isset($param['lang']) && $surveyid) - { - $templang = sanitize_languagecode($param['lang']); - $clang = SetSurveyLanguage( $surveyid, $templang); - UpdateSessionGroupList($surveyid, $templang); // to refresh the language strings in the group list session variable - UpdateFieldArray(); // to refresh question titles and question text - } + //CHECK FOR REQUIRED INFORMATION (sid) + if (!$surveyid) + { + if(isset($param['lang'])) + { + $baselang = sanitize_languagecode($param['lang']); + } + elseif (!isset($baselang)) + { + $baselang = $this->config->item("defaultlang"); + } + $clang = $this->_loadLimesurveyLang($baselang); + if(!isset($defaulttemplate)) + { + $defaulttemplate="default"; + } + $languagechanger = makelanguagechanger(); + //Find out if there are any publicly available surveys + $query = "SELECT a.sid, b.surveyls_title, a.publicstatistics + FROM ".$this->db->dbprefix('surveys')." AS a + INNER JOIN ".$this->db->dbprefix('surveys_languagesettings')." AS b + ON ( surveyls_survey_id = a.sid AND surveyls_language = a.language ) + WHERE surveyls_survey_id=a.sid + AND surveyls_language=a.language + AND surveyls_language='$baselang' + AND a.active='Y' + AND a.listpublic='Y' + AND ((a.expires >= '".date("Y-m-d H:i")."') OR (a.expires is null)) + AND ((a.startdate <= '".date("Y-m-d H:i")."') OR (a.startdate is null)) + ORDER BY surveyls_title"; + $result = db_execute_assoc($query,false,true) or die("Could not connect to database. If you try to install LimeSurvey please refer to the installation docs and/or contact the system administrator of this webpage."); //Checked + $list=array(); + if($result->num_rows() > 0) + { + foreach($result->result_array() as $rows) + { + $link = "
  • \n"; + if ($rows['publicstatistics'] == 'Y') $link .= "(".$clang->gT('View statistics').")"; + $link .= "
  • \n"; + $list[]=$link; + } + } + if(count($list) < 1) + { + $list[]="
  • ".$clang->gT("No available surveys")."
  • "; + } + $surveylist=array( + "nosid"=>$clang->gT("You have not provided a survey identification number"), + "contact"=>sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$this->config->item("siteadminname"),encodeEmail($this->config->item("siteadminemail"))), + "listheading"=>$clang->gT("The following surveys are available:"), + "list"=>implode("\n",$list), + ); + + $thissurvey['name'] = $this->config->item("sitename"); + $thissurvey['templatedir'] = $defaulttemplate; + + $data['thissurvey'] = $thissurvey; + //$data['privacy'] = $privacy; + $data['surveylist'] = $surveylist; + $data['surveyid'] = $surveyid; + $data['templatedir'] = sGetTemplatePath($defaulttemplate); + $data['templateurl'] = sGetTemplateURL($defaulttemplate)."/"; + $data['templatename'] = $defaulttemplate; + $data['sitename'] = $this->config->item("sitename"); + $data['languagechanger'] = $languagechanger; + + //A nice exit + sendcacheheaders(); + doHeader(); + $this->_printTemplateContent(sGetTemplatePath($defaulttemplate)."/startpage.pstpl", $data, __LINE__); + + $this->_printTemplateContent(sGetTemplatePath($defaulttemplate)."/surveylist.pstpl", $data, __LINE__); + + $this->_killPage($redata, __LINE__); + } - if (isset($_SESSION['s_lang'])) - { - $clang = SetSurveyLanguage( $surveyid, $_SESSION['s_lang']); - } - elseif (isset($surveyid) && $surveyid) - { - $baselang = GetBaseLanguageFromSurveyID($surveyid); - $clang = SetSurveyLanguage( $surveyid, $baselang); - } - else - { - $baselang=$defaultlang; - } + // Get token + if (!isset($token)) + { + $token=$clienttoken; + } - if (isset($param['embedded_inc'])) - { - safe_die('You cannot start this script directly'); - } + //GET BASIC INFORMATION ABOUT THIS SURVEY + $totalBoilerplatequestions =0; + $thissurvey=getSurveyInfo($surveyid, $_SESSION['s_lang']); + if (isset($param['newtest']) && $param['newtest'] == "Y") + { + //Removes any existing timer cookies so timers will start again + setcookie ("limesurvey_timers", "", time() - 3600); + } - //CHECK FOR REQUIRED INFORMATION (sid) - if (!$surveyid) - { - if(isset($param['lang'])) - { - $baselang = sanitize_languagecode($param['lang']); - } - elseif (!isset($baselang)) - { - $baselang=$defaultlang; - } - $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); - $clang = $this->limesurvey_lang; - if(!isset($defaulttemplate)) - { - $defaulttemplate="default"; - } - $languagechanger = makelanguagechanger(); - //Find out if there are any publicly available surveys - $query = "SELECT a.sid, b.surveyls_title, a.publicstatistics - FROM ".$this->db->dbprefix('surveys')." AS a - INNER JOIN ".$this->db->dbprefix('surveys_languagesettings')." AS b - ON ( surveyls_survey_id = a.sid AND surveyls_language = a.language ) - WHERE surveyls_survey_id=a.sid - AND surveyls_language=a.language - AND surveyls_language='$baselang' - AND a.active='Y' - AND a.listpublic='Y' - AND ((a.expires >= '".date("Y-m-d H:i")."') OR (a.expires is null)) - AND ((a.startdate <= '".date("Y-m-d H:i")."') OR (a.startdate is null)) - ORDER BY surveyls_title"; - $result = db_execute_assoc($query,false,true) or die("Could not connect to database. If you try to install LimeSurvey please refer to the installation docs and/or contact the system administrator of this webpage."); //Checked - $list=array(); - if($result->num_rows() > 0) - { - foreach($result->result_array() as $rows) - { - $link = "
  • \n"; - if ($rows['publicstatistics'] == 'Y') $link .= "(".$clang->gT('View statistics').")"; - $link .= "
  • \n"; - $list[]=$link; - } - } - if(count($list) < 1) - { - $list[]="
  • ".$clang->gT("No available surveys")."
  • "; - } - $surveylist=array( - "nosid"=>$clang->gT("You have not provided a survey identification number"), - "contact"=>sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$siteadminname,encodeEmail($siteadminemail)), - "listheading"=>$clang->gT("The following surveys are available:"), - "list"=>implode("\n",$list), - ); - - $thissurvey['name']=$sitename; - $thissurvey['templatedir']=$defaulttemplate; - - $data['thissurvey'] = $thissurvey; - //$data['privacy'] = $privacy; - $data['surveylist'] = $surveylist; - $data['surveyid'] = $surveyid; - $data['templatedir'] = sGetTemplatePath($defaulttemplate); - $data['templateurl'] = sGetTemplateURL($defaulttemplate)."/"; - $data['templatename'] = $defaulttemplate; - $data['sitename'] = $sitename; - $data['languagechanger'] = $languagechanger; - - //A nice exit - sendcacheheaders(); - doHeader(); - echo templatereplace(file_get_contents(sGetTemplatePath($defaulttemplate)."/startpage.pstpl"),array(),$data,'survey[503]'); - - echo templatereplace(file_get_contents(sGetTemplatePath($defaulttemplate)."/surveylist.pstpl"),array(),$data,'survey[505]'); - - echo templatereplace(file_get_contents(sGetTemplatePath($defaulttemplate)."/endpage.pstpl"),array(),$data,'survey[507]'); - doFooter(); - exit; - } - // Get token - if (!isset($token)) - { - $token=$clienttoken; - } - //GET BASIC INFORMATION ABOUT THIS SURVEY - $totalBoilerplatequestions =0; - $thissurvey=getSurveyInfo($surveyid, $_SESSION['s_lang']); + //SEE IF SURVEY USES TOKENS AND GROUP TOKENS + $i = 0; //$tokensexist = 0; + if ($surveyExists == 1 && tableExists('tokens_'.$thissurvey['sid'])) + { + $tokensexist = 1; - if (isset($param['newtest']) && $param['newtest'] == "Y") - { - //Removes any existing timer cookies so timers will start again - setcookie ("limesurvey_timers", "", time() - 3600); - } + } + else + { + $tokensexist = 0; + unset($_POST['token']); + unset($param['token']); + unset($token); + unset($clienttoken); + } - //SEE IF SURVEY USES TOKENS AND GROUP TOKENS - $i = 0; //$tokensexist = 0; - if ($surveyexists == 1 && tableExists('tokens_'.$thissurvey['sid'])) - { - $tokensexist = 1; - } - else - { - $tokensexist = 0; - unset($_POST['token']); - unset($param['token']); - unset($token); - unset($clienttoken); - } + //SET THE TEMPLATE DIRECTORY + if (!$thissurvey['templatedir']) + { + $thistpl = sGetTemplatePath($defaulttemplate); + } + else + { + $thistpl = sGetTemplatePath($thissurvey['templatedir']); + } + $timeadjust = $this->config->item("timeadjust"); + //MAKE SURE SURVEY HASN'T EXPIRED + if ($thissurvey['expiry']!='' and date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)>$thissurvey['expiry'] && $thissurvey['active']!='N') + { + sendcacheheaders(); + doHeader(); - //SET THE TEMPLATE DIRECTORY - if (!$thissurvey['templatedir']) - { - $thistpl=sGetTemplatePath($defaulttemplate); - } - else - { - $thistpl=sGetTemplatePath($thissurvey['templatedir']); - } + $redata = compact(array_keys(get_defined_vars())); + $this->_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("This survey is no longer available."), + sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']) + ); + + $this->_killPage($redata, __LINE__, $thistpl); + } + //MAKE SURE SURVEY IS ALREADY VALID + if ($thissurvey['startdate']!='' and date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)<$thissurvey['startdate'] && $thissurvey['active']!='N') + { + sendcacheheaders(); + doHeader(); - $timeadjust = $this->config->item("timeadjust"); - //MAKE SURE SURVEY HASN'T EXPIRED - if ($thissurvey['expiry']!='' and date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)>$thissurvey['expiry'] && $thissurvey['active']!='N') - { + $redata = compact(array_keys(get_defined_vars())); + $this->_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("This survey is not yet started."), + sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']) + ); + + $this->_killPage($redata, __LINE__, $thistpl); + } - sendcacheheaders(); - doHeader(); + //CHECK FOR PREVIOUSLY COMPLETED COOKIE + //If cookies are being used, and this survey has been completed, a cookie called "PHPSID[sid]STATUS" will exist (ie: SID6STATUS) and will have a value of "COMPLETE" + $cookiename="PHPSID".returnglobal('sid')."STATUS"; + if (isset($_COOKIE[$cookiename]) && $_COOKIE[$cookiename] == "COMPLETE" && $thissurvey['usecookie'] == "Y" && $tokensexist != 1 && (!isset($param['newtest']) || $param['newtest'] != "Y")) + { + sendcacheheaders(); + doHeader(); $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'survey[569]'); - echo "\t
    \n" - ."\t

    \n" - ."\t".$clang->gT("This survey is no longer available.")."

    \n" - ."\t".sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']).".

    \n" - ."\t

    \n" - ."\t
    \n"; - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[577]'); - doFooter(); - exit; - } + $this->_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + $this->_printMessage( + $clang->gT("Error"), + $clang->gT("You have already completed this survey."), + sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']) + ); + + $this->_killPage($redata, __LINE__, $thistpl); + } - //MAKE SURE SURVEY IS ALREADY VALID - if ($thissurvey['startdate']!='' and date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)<$thissurvey['startdate'] && $thissurvey['active']!='N') - { - sendcacheheaders(); - doHeader(); - $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'survey[589]'); - echo "\t
    \n" - ."\t

    \n" - ."\t".$clang->gT("This survey is not yet started.")."

    \n" - ."\t".sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail']).".

    \n" - ."\t

    \n" - ."\t
    \n"; - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[597]'); - doFooter(); - exit; - } + //CHECK IF SURVEY ID DETAILS HAVE CHANGED + if (isset($_SESSION['oldsid'])) + { + $oldsid=$_SESSION['oldsid']; + } - //CHECK FOR PREVIOUSLY COMPLETED COOKIE - //If cookies are being used, and this survey has been completed, a cookie called "PHPSID[sid]STATUS" will exist (ie: SID6STATUS) and will have a value of "COMPLETE" - $cookiename="PHPSID".returnglobal('sid')."STATUS"; - if (isset($_COOKIE[$cookiename]) && $_COOKIE[$cookiename] == "COMPLETE" && $thissurvey['usecookie'] == "Y" && $tokensexist != 1 && (!isset($param['newtest']) || $param['newtest'] != "Y")) - { - sendcacheheaders(); - doHeader(); + if (!isset($oldsid)) + { + $_SESSION['oldsid'] = $surveyid; + } - $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'survey[611]'); - echo "\t
    \n" - ."\t

    \n" - ."\t".$clang->gT("Error")."

    \n" - ."\t".$clang->gT("You have already completed this survey.")."

    \n" - ."\t".sprintf($clang->gT("Please contact %s ( %s ) for further assistance."),$thissurvey['adminname'],$thissurvey['adminemail'])."\n" - ."\t

    \n" - ."\t
    \n"; - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[620]'); - doFooter(); - exit; - } + if (isset($oldsid) && $oldsid && $oldsid != $surveyid) + { + $savesessionvars=Array(); + if (isset($_SESSION['USER_RIGHT_PREVIEW'])) + { + $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; + $savesessionvars["loginID"]=$_SESSION['loginID']; + $savesessionvars["user"]=$_SESSION['user']; + } + session_unset(); + $_SESSION['oldsid']=$surveyid; + foreach ($savesessionvars as $sesskey => $sessval) + { + $_SESSION[$sesskey]=$sessval; + } + } - //CHECK IF SURVEY ID DETAILS HAVE CHANGED - if (isset($_SESSION['oldsid'])) - { - $oldsid=$_SESSION['oldsid']; - } - if (!isset($oldsid)) - { - $_SESSION['oldsid'] = $surveyid; - } + if (isset($_GET['loadall']) && $_GET['loadall'] == "reload") + { + if (returnglobal('loadname') && returnglobal('loadpass')) + { + $_POST['loadall']="reload"; + } + } - if (isset($oldsid) && $oldsid && $oldsid != $surveyid) - { - $savesessionvars=Array(); - if (isset($_SESSION['USER_RIGHT_PREVIEW'])) - { - $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; - $savesessionvars["loginID"]=$_SESSION['loginID']; - $savesessionvars["user"]=$_SESSION['user']; - } - session_unset(); - $_SESSION['oldsid']=$surveyid; - foreach ($savesessionvars as $sesskey => $sessval) - { - $_SESSION[$sesskey]=$sessval; - } - } + //LOAD SAVED SURVEY + if (isset($_POST['loadall']) && $_POST['loadall'] == "reload") + { + $errormsg=""; + if ( !isset($param['loadname']) || $param['loadname'] == null ) + { + $errormsg .= $clang->gT("You did not provide a name")."
    \n"; + } + if (!isset($param['loadpass']) || $param['loadpass'] == null ) + { + $errormsg .= $clang->gT("You did not provide a password")."
    \n"; + } + // if security question answer is incorrect + // Not called if scid is set in GET params (when using email save/reload reminder URL) + if (function_exists("ImageCreate") && captcha_enabled('saveandloadscreen',$thissurvey['usecaptcha'])) + { + if ( (!isset($_POST['loadsecurity']) || + !isset($_SESSION['secanswer']) || + $_POST['loadsecurity'] != $_SESSION['secanswer']) && + !isset($_GET['scid'])) + { + $errormsg .= $clang->gT("The answer to the security question is incorrect.")."
    \n"; + } + } + // Load session before loading the values from the saved data + if (isset($_GET['loadall'])) + { + buildsurveysession(); + } - if (isset($_GET['loadall']) && $_GET['loadall'] == "reload") - { - if (returnglobal('loadname') && returnglobal('loadpass')) - { - $_POST['loadall']="reload"; - } - } + $_SESSION['holdname'] = $param['loadname']; //Session variable used to load answers every page. + $_SESSION['holdpass'] = $param['loadpass']; //Session variable used to load answers every page. - //LOAD SAVED SURVEY - if (isset($_POST['loadall']) && $_POST['loadall'] == "reload") - { - $errormsg=""; - // if (loadname is not set) or if ((loadname is set) and (loadname is NULL)) - if (!isset($loadname) || (isset($loadname) && ($loadname == null))) - { - $errormsg .= $clang->gT("You did not provide a name")."
    \n"; - } - // if (loadpass is not set) or if ((loadpass is set) and (loadpass is NULL)) - if (!isset($loadpass) || (isset($loadpass) && ($loadpass == null))) - { - $errormsg .= $clang->gT("You did not provide a password")."
    \n"; - } - - // if security question answer is incorrect - // Not called if scid is set in GET params (when using email save/reload reminder URL) - if (function_exists("ImageCreate") && captcha_enabled('saveandloadscreen',$thissurvey['usecaptcha'])) - { - if ( (!isset($_POST['loadsecurity']) || - !isset($_SESSION['secanswer']) || - $_POST['loadsecurity'] != $_SESSION['secanswer']) && - !isset($_GET['scid'])) - { - $errormsg .= $clang->gT("The answer to the security question is incorrect.")."
    \n"; - } - } - - // Load session before loading the values from the saved data - if (isset($_GET['loadall'])) - { - buildsurveysession(); - } - - $_SESSION['holdname']=$loadname; //Session variable used to load answers every page. - $_SESSION['holdpass']=$loadpass; //Session variable used to load answers every page. - - if ($errormsg == "") loadanswers(); - $move = "movenext"; - - if ($errormsg) - { - $_POST['loadall'] = $clang->gT("Load Unfinished Survey"); - } - } - //Allow loading of saved survey - if (isset($_POST['loadall']) && $_POST['loadall'] == $clang->gT("Load Unfinished Survey")) - { - $vars = compact(array_keys(get_defined_vars())); - $this->load->library("load_answers"); - $this->load_answers->run($vars); - } + if ($errormsg == "") loadanswers(); + $move = "movenext"; + if ($errormsg) + { + $_POST['loadall'] = $clang->gT("Load Unfinished Survey"); + } + } + //Allow loading of saved survey + if (isset($_POST['loadall']) && $_POST['loadall'] == $clang->gT("Load Unfinished Survey")) + { + $redata = compact(array_keys(get_defined_vars())); + $this->load->library("load_answers"); + $this->load_answers->run($redata); + } - //Check if TOKEN is used for EVERY PAGE - //This function fixes a bug where users able to submit two surveys/votes - //by checking that the token has not been used at each page displayed. - // bypass only this check at first page (Step=0) because - // this check is done in buildsurveysession and error message - // could be more interresting there (takes into accound captcha if used) - if ($tokensexist == 1 && isset($token) && $token && - isset($_SESSION['step']) && $_SESSION['step']>0 && db_tables_exist($dbprefix.'tokens_'.$surveyid)) - { - //check if tokens actually haven't been already used - $areTokensUsed = usedTokens(trim(strip_tags(returnglobal('token'))),$surveyid); - // check if token actually does exist - // check also if it is allowed to change survey after completion - if ($thissurvey['alloweditaftercompletion'] == 'Y' ) { - $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." "; - } else { - $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." AND (completed = 'N' or completed='')"; - } - $tkresult = db_execute_assoc($tkquery); //Checked - $tokendata = $tkresult->row_array(); - if ($tkresult->num_rows()==0 || $areTokensUsed) - { - sendcacheheaders(); - doHeader(); - //TOKEN DOESN'T EXIST OR HAS ALREADY BEEN USED. EXPLAIN PROBLEM AND EXIT + + //Check if TOKEN is used for EVERY PAGE + //This function fixes a bug where users able to submit two surveys/votes + //by checking that the token has not been used at each page displayed. + // bypass only this check at first page (Step=0) because + // this check is done in buildsurveysession and error message + // could be more interresting there (takes into accound captcha if used) + if ($tokensexist == 1 && isset($token) && $token && + isset($_SESSION['step']) && $_SESSION['step']>0 && db_tables_exist($this->db->dbprefix('tokens_'.$surveyid))) + { + //check if tokens actually haven't been already used + $areTokensUsed = usedTokens(trim(strip_tags(returnglobal('token'))),$surveyid); + // check if token actually does exist + // check also if it is allowed to change survey after completion + if ($thissurvey['alloweditaftercompletion'] == 'Y' ) { + $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." "; + } else { + $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." AND (completed = 'N' or completed='')"; + } + $tkresult = db_execute_assoc($tkquery); //Checked + $tokendata = $tkresult->row_array(); + if ($tkresult->num_rows()==0 || $areTokensUsed) + { + sendcacheheaders(); + doHeader(); + //TOKEN DOESN'T EXIST OR HAS ALREADY BEEN USED. EXPLAIN PROBLEM AND EXIT $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'survey[745]'); - echo templatereplace(file_get_contents("$thistpl/survey.pstpl"),array(),$redata,'survey[746]'); - echo "\t
    \n" - ."\t

    \n" - ."\t".$clang->gT("This is a controlled survey. You need a valid token to participate.")."

    \n" - ."\t".$clang->gT("The token you have provided is either not valid, or has already been used.")."\n" - ."\t".sprintf($clang->gT("For further information please contact %s"), $thissurvey['adminname'] - ." (" - ."{$thissurvey['adminemail']})")."\n" - ."\t

    \n" - ."\t
    \n"; - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[757]'); - killSession(); - doFooter(); - exit; - } - } - if ($tokensexist == 1 && isset($token) && $token && db_tables_exist($dbprefix.'tokens_'.$surveyid)) //check if token is in a valid time frame - { - // check also if it is allowed to change survey after completion - if ($thissurvey['alloweditaftercompletion'] == 'Y' ) { - $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." "; - } else { - $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." AND (completed = 'N' or completed='')"; - } - $tkresult = db_execute_assoc($tkquery); //Checked - $tokendata = $tkresult->row_array(); - if (isset($tokendata['validfrom']) && (trim($tokendata['validfrom'])!='' && $tokendata['validfrom']>date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)) || - isset($tokendata['validuntil']) && (trim($tokendata['validuntil'])!='' && $tokendata['validuntil']_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + $this->_printTemplateContent($thistpl.'/survey.pstpl', $redata, __LINE__); + $this->_printMessage( + null, + $clang->gT("This is a controlled survey. You need a valid token to participate."), + sprintf($clang->gT("For further information please contact %s"), $thissurvey['adminname']." ("."{$thissurvey['adminemail']})") + ); + + $this->_killPage($redata, __LINE__, $thistpl, true); + } + } + if ($tokensexist == 1 && isset($token) && $token && db_tables_exist($this->db->dbprefix('tokens_'.$surveyid))) //check if token is in a valid time frame + { + // check also if it is allowed to change survey after completion + if ($thissurvey['alloweditaftercompletion'] == 'Y' ) { + $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." "; + } else { + $tkquery = "SELECT * FROM ".$this->db->dbprefix('tokens_'.$surveyid)." WHERE token=".$this->db->escape($token)." AND (completed = 'N' or completed='')"; + } + $tkresult = db_execute_assoc($tkquery); //Checked + $tokendata = $tkresult->row_array(); + if (isset($tokendata['validfrom']) && (trim($tokendata['validfrom'])!='' && $tokendata['validfrom']>date_shift(date("Y-m-d H:i:s"), "Y-m-d H:i:s", $timeadjust)) || + isset($tokendata['validuntil']) && (trim($tokendata['validuntil'])!='' && $tokendata['validuntil']\n" - ."\t

    \n" - ."\t".$clang->gT("We are sorry but you are not allowed to enter this survey.")."

    \n" - ."\t".$clang->gT("Your token seems to be valid but can be used only during a certain time period.")."
    \n" - ."\t".sprintf($clang->gT("For further information please contact %s"), $thissurvey['adminname'] - ." (" - ."{$thissurvey['adminemail']})")."\n" - ."\t

    \n" - ."\t\n"; - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[793]'); - doFooter(); - killSession(); - exit; - } - } + $this->_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + $this->_printTemplateContent($thistpl.'/survey.pstpl', $redata, __LINE__); + $this->_printMessage( + null, + $clang->gT("We are sorry but you are not allowed to enter this survey."), + $clang->gT("Your token seems to be valid but can be used only during a certain time period."), + sprintf($clang->gT("For further information please contact %s"), $thissurvey['adminname']." ("."{$thissurvey['adminemail']})") + ); + $this->_killPage($redata, __LINE__, $thistpl, true); + } + } - //Clear session and remove the incomplete response if requested. - if (isset($move) && $move == "clearall") - { - $s_lang = $_SESSION['s_lang']; - if (isset($_SESSION['srid'])) - { - // find out if there are any fuqt questions - checked - $fieldmap = createFieldMap($surveyid); - foreach ($fieldmap as $field) - { - if ($field['type'] == "|" && !strpos($field['fieldname'], "_filecount")) - { - if (!isset($qid)) { $qid = array(); } - $qid[] = $field['fieldname']; - } - } - - // if yes, extract the response json to those questions - if (isset($qid)) - { - $query = "SELECT * FROM ".$this->db->dbprefix("survey_".$surveyid)." WHERE id=".$_SESSION['srid']; - $result = db_execute_assoc($query); - foreach($result->result_array() as $row) - { - foreach ($qid as $question) - { - $json = $row[$question]; - if ($json == "" || $json == NULL) - continue; - - // decode them - $phparray = json_decode($json); - - foreach ($phparray as $metadata) - { - $target = $this->config->item("uploaddir")."/surveys/".$surveyid."/files/"; - // delete those files - unlink($target.$metadata->filename); - } - } - } - } - // done deleting uploaded files - - - // delete the response but only if not already completed - db_execute_assoc('DELETE FROM '.$this->db->dbprefix('survey_'.$surveyid).' WHERE id='.$_SESSION['srid']." AND submitdate IS NULL"); - - // also delete a record from saved_control when there is one - db_execute_assoc('DELETE FROM '.$this->db->dbprefix('saved_control'). ' WHERE srid='.$_SESSION['srid'].' AND sid='.$surveyid); - } - session_unset(); - session_destroy(); - setcookie(session_name(),"EXPIRED",time()-120); - sendcacheheaders(); - if (isset($_GET['redirect'])) - { - session_write_close(); - header("Location: {$_GET['redirect']}"); - } - doHeader(); + + + //Clear session and remove the incomplete response if requested. + if (isset($move) && $move == "clearall") + { + $s_lang = $_SESSION['s_lang']; + if (isset($_SESSION['srid'])) + { + // find out if there are any fuqt questions - checked + $fieldmap = createFieldMap($surveyid); + foreach ($fieldmap as $field) + { + if ($field['type'] == "|" && !strpos($field['fieldname'], "_filecount")) + { + if (!isset($qid)) { $qid = array(); } + $qid[] = $field['fieldname']; + } + } + + // if yes, extract the response json to those questions + if (isset($qid)) + { + $query = "SELECT * FROM ".$this->db->dbprefix("survey_".$surveyid)." WHERE id=".$_SESSION['srid']; + $result = db_execute_assoc($query); + foreach($result->result_array() as $row) + { + foreach ($qid as $question) + { + $json = $row[$question]; + if ($json == "" || $json == NULL) + continue; + + // decode them + $phparray = json_decode($json); + + foreach ($phparray as $metadata) + { + $target = $this->config->item("uploaddir")."/surveys/".$surveyid."/files/"; + // delete those files + unlink($target.$metadata->filename); + } + } + } + } + // done deleting uploaded files + + + // delete the response but only if not already completed + db_execute_assoc('DELETE FROM '.$this->db->dbprefix('survey_'.$surveyid).' WHERE id='.$_SESSION['srid']." AND submitdate IS NULL"); + + // also delete a record from saved_control when there is one + db_execute_assoc('DELETE FROM '.$this->db->dbprefix('saved_control'). ' WHERE srid='.$_SESSION['srid'].' AND sid='.$surveyid); + } + session_unset(); + session_destroy(); + setcookie(session_name(),"EXPIRED",time()-120); + sendcacheheaders(); + if (isset($_GET['redirect'])) + { + session_write_close(); + header("Location: {$_GET['redirect']}"); + } + doHeader(); $redata = compact(array_keys(get_defined_vars())); - echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'survey[864]'); - echo "\n\n\n" - ."\t\n\n"; - - //Present the clear all page using clearall.pstpl template - echo templatereplace(file_get_contents("$thistpl/clearall.pstpl"),array(),$redata,'survey[876]'); - - echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'survey[878]'); - doFooter(); - exit; - } + $this->_printTemplateContent($thistpl.'/startpage.pstpl', $redata, __LINE__); + echo "\n\n\n" + ."\t\n\n"; + + //Present the clear all page using clearall.pstpl template + $this->_printTemplateContent($thistpl.'/clearall.pstpl', $redata, __LINE__); + + $this->_killPage($redata, __LINE__, $thistpl); + } - if (isset($param['newtest']) && $param['newtest'] == "Y") - { - $savesessionvars=Array(); - if (isset($_SESSION['USER_RIGHT_PREVIEW'])) - { - $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; - $savesessionvars["loginID"]=$_SESSION['loginID']; - $savesessionvars["user"]=$_SESSION['user']; - } - session_unset(); - $_SESSION['oldsid']=$surveyid; - foreach ($savesessionvars as $sesskey => $sessval) - { - $_SESSION[$sesskey]=$sessval; - } - //DELETE COOKIE (allow to use multiple times) - setcookie($cookiename, "INCOMPLETE", time()-120); - //echo "Reset Cookie!"; - } + if (isset($param['newtest']) && $param['newtest'] == "Y") + { + $savesessionvars=Array(); + if (isset($_SESSION['USER_RIGHT_PREVIEW'])) + { + $savesessionvars["USER_RIGHT_PREVIEW"]=$surveyid; + $savesessionvars["loginID"]=$_SESSION['loginID']; + $savesessionvars["user"]=$_SESSION['user']; + } + session_unset(); + $_SESSION['oldsid']=$surveyid; + foreach ($savesessionvars as $sesskey => $sessval) + { + $_SESSION[$sesskey]=$sessval; + } + //DELETE COOKIE (allow to use multiple times) + setcookie($cookiename, "INCOMPLETE", time()-120); + //echo "Reset Cookie!"; + } - //Check to see if a refering URL has been captured. - GetReferringUrl(); - // Let's do this only if - // - a saved answer record hasn't been loaded through the saved feature - // - the survey is not anonymous - // - the survey is active - // - a token information has been provided - // - the survey is setup to allow token-response-persistence + //Check to see if a refering URL has been captured. + GetReferringUrl(); + // Let's do this only if + // - a saved answer record hasn't been loaded through the saved feature + // - the survey is not anonymous + // - the survey is active + // - a token information has been provided + // - the survey is setup to allow token-response-persistence - if ($thissurvey['tokenanswerspersistence'] == 'Y' && !isset($_SESSION['srid']) && $thissurvey['anonymized'] == "N" && $thissurvey['active'] == "Y" && isset($token) && $token !='') - { + if ($thissurvey['tokenanswerspersistence'] == 'Y' && !isset($_SESSION['srid']) && $thissurvey['anonymized'] == "N" && $thissurvey['active'] == "Y" && isset($token) && $token !='') + { - // load previous answers if any (dataentry with nosubmit) - $srquery="SELECT id FROM {$thissurvey['tablename']}" - . " WHERE {$thissurvey['tablename']}.token='".$this->db->escape($token)."' order by id desc"; + // load previous answers if any (dataentry with nosubmit) + $srquery="SELECT id FROM {$thissurvey['tablename']}" + . " WHERE {$thissurvey['tablename']}.token='".$this->db->escape($token)."' order by id desc"; $result = db_select_limit_assoc($srquery,1); if ($result->num_rows()>0) @@ -941,67 +755,303 @@ function action() $row=reset($result->result_array()); if($row['submitdate']=='' || ($row['submitdate']!='' && $thissurvey['alloweditaftercompletion'] == 'Y')) $_SESSION['srid'] = $row['id']; - } - buildsurveysession(); - loadanswers(); - } + } + buildsurveysession(); + loadanswers(); + } - // SAVE POSTED ANSWERS TO DATABASE IF MOVE (NEXT,PREV,LAST, or SUBMIT) or RETURNING FROM SAVE FORM - if (isset($move) || isset($_POST['saveprompt'])) - { - $args = compact(array_keys(get_defined_vars())); - //save.php - $this->load->library("Save"); - $this->save->run($args); - - // RELOAD THE ANSWERS INCASE SOMEONE ELSE CHANGED THEM - if ($thissurvey['active'] == "Y" && - ( $thissurvey['allowsave'] == "Y" || $thissurvey['tokenanswerspersistence'] == "Y") ) - { - loadanswers(); - } - } + // SAVE POSTED ANSWERS TO DATABASE IF MOVE (NEXT,PREV,LAST, or SUBMIT) or RETURNING FROM SAVE FORM + if (isset($move) || isset($_POST['saveprompt'])) + { + $redata = compact(array_keys(get_defined_vars())); + //save.php + $this->load->library("Save"); + $this->save->run($redata); - if (isset($_REQUEST['action']) && ($_REQUEST['action'] == 'previewgroup')){ - $thissurvey['format'] = 'G'; - buildsurveysession(); - } + // RELOAD THE ANSWERS INCASE SOMEONE ELSE CHANGED THEM + if ($thissurvey['active'] == "Y" && + ( $thissurvey['allowsave'] == "Y" || $thissurvey['tokenanswerspersistence'] == "Y") ) + { + loadanswers(); + } + } - sendcacheheaders(); + if (isset($_REQUEST['action']) && ($_REQUEST['action'] == 'previewgroup')){ + $thissurvey['format'] = 'G'; + buildsurveysession(); + } - //Send local variables to the appropriate survey type - $args = compact(array_keys(get_defined_vars())); + sendcacheheaders(); - //CALL APPROPRIATE SCRIPT - switch ($thissurvey['format']) - { - case "A": //All in one - //require_once("survey.php"); - $this->load->library("Survey_format"); - $this->survey_format->run($args); - break; - case "S": //One at a time - //require_once("question.php"); - $this->load->library("Question_format"); - $this->question_format->run($args); - break; - case "G": //Group at a time - $this->load->library("Group_format"); - $this->group_format->run($args); - break; - default: - //require_once("question.php"); - $this->load->library("Question_format"); - $this->question_format->run($args); - } + //Send local variables to the appropriate survey type + $redata = compact(array_keys(get_defined_vars())); + + //CALL APPROPRIATE SCRIPT + switch ($thissurvey['format']) + { + case "A": //All in one + //require_once("survey.php"); + $this->load->library("Survey_format"); + $this->survey_format->run($redata); + break; + case "S": //One at a time + //require_once("question.php"); + $this->load->library("Question_format"); + $this->question_format->run($redata); + break; + case "G": //Group at a time + $this->load->library("Group_format"); + $this->group_format->run($redata); + break; + default: + //require_once("question.php"); + $this->load->library("Question_format"); + $this->question_format->run($redata); + } if (isset($_POST['saveall']) || isset($flashmessage)) { echo ""; } + } + + function _getParameters($args = array(), $post = array()) + { + $param = array(); + if($args[0]==__CLASS__) array_shift($args); + if(count($args)%2 == 0) { + for ($i = 0; $i < count($args); $i+=2) { + //Sanitize input from URL with returnglobal + $param[$args[$i]] = returnglobal($args[$i], $args[$i+1]); + } + } + + if( !isset($param['action']) ) + $param['action'] = isset($post['action']) ? $post['action'] : null; + if( !isset($param['newtest']) ) + $param['newtest'] = isset($post['newtest']) ? $post['newtest'] : null; + if( !isset($param['gid']) ) + $param['gid'] = isset($post['gid']) ? $post['gid'] : null; + + if ( !isset($param['sid']) ) + $param['sid'] = returnglobal('sid'); + if ( !isset($param['loadname']) ) + $param['loadname'] = returnglobal('loadname'); + if ( !isset($param['loadpass']) ) + $param['loadpass'] = returnglobal('loadpass'); + if ( !isset($param['scid']) ) + $param['scid'] = returnglobal('scid'); + if ( !isset($param['thisstep']) ) + $param['thisstep'] = returnglobal('thisstep'); + if ( !isset($param['move']) ) + $param['move'] = returnglobal('move'); + if ( !isset($param['token']) ) + $param['token'] = returnglobal('token'); + + if ( !isset($param['thisstep']) ) + $param['thisstep'] = ''; + + return $param; + } + + function _getSessionName($surveyId) + { + // Compute the Session name + // Session name is based: + // * on this specific limesurvey installation (Value SessionName in DB) + // * on the surveyid (from Get or Post param). If no surveyid is given we are on the public surveys portal + $sSessionname = getGlobalSetting('SessionName'); + if ($sSessionname != '') + { + if ($surveyId) + { + return $sSessionname.'-runtime-'.$surveyId; + } + return $sSessionname.'-runtime-publicportal'; + } + return 'LimeSurveyRuntime-'.$surveyId; + } + + function _setSessionToSurvey($surveyId) + { + $sSessionname = $this->_getSessionName($surveyId); + + // Establish / Switch to survey session + // Import data from current session (if available) to survey + // session if the survey session has no data. - } + $__SESSION = array(); // session data copy store + $oSess = new LS_PHP_Session(); + if ($oSess->changeTo($sSessionname)) + { + // Needed to call session_start() below. + $__SESSION =& $_SESSION; // reference current session data. + unset($_SESSION); + $_SESSION = array(); + } + else + { + session_name($sSessionname); + } + unset($oSess); + + session_set_cookie_params(0,$this->config->item("relativeurl")); + if (empty($_SESSION)) // the $_SESSION variable can be empty if register_globals is on + { + @session_start(); + if (empty($_SESSION)) // if this session is new, import old session + { + $_SESSION = $__SESSION; + unset($__SESSION); + } + $this->session->bind_userdata(); // que? + } + } + + function _loadRequiredHelpersAndLibraries() + { + //Load helpers, libraries and config vars + $this->load->helper("database"); + $this->load->helper("frontend"); + $this->load->helper("surveytranslator"); + $this->load->library("Dtexts"); + } + + function _loadLimesurveyLang($mvSurveyIdOrBaseLang) + { + if ( is_int($mvSurveyIdOrBaseLang) ) + { + $baselang = GetBaseLanguageFromSurveyID($surveyId); + } + else + { + $baselang = $mvSurveyIdOrBaseLang; + } + + $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); + + return $this->limesurvey_lang; + } + + function _surveyExistsAndIsActive($surveyId) + { + $isSurveyActive = false; + $surveyExists = false; + + if ($surveyId) + { + $aRow = db_execute_assoc("SELECT active FROM ".$this->db->dbprefix('surveys')." WHERE sid='".$surveyId."'")->row_array(); + if (isset($aRow['active'])) + { + $surveyExists = true; + if($aRow['active'] == 'Y') + { + $isSurveyActive = true; + } + } + } + + return array($surveyExists, $isSurveyActive); + } + + + function _isClientTokenDifferentFromSessionToken($clientToken) + { + return $clientToken != '' && isset($_SESSION['token']) && $clientToken != $_SESSION['token']; + } + + function _isSurveyFinished() + { + return isset($_SESSION['finished']) && $_SESSION['finished'] === true; + } + + function _isPreviewAction($param = array()) + { + return isset($param['action']) && $param['action'] == 'previewgroup'; + } + + function _surveyCantBeViewedWithCurrentPreviewAccess($surveyid, $bIsSurveyActive, $bSurveyExists) + { + $bSurveyPreviewRequireAuth = $this->config->item('surveyPreview_require_Auth'); + return $surveyid && $bIsSurveyActive === false && $bSurveyExists && isset($bSurveyPreviewRequireAuth) && $bSurveyPreviewRequireAuth == true && !$this->_canUserPreviewSurvey($surveyid); + } + + function _canUserPreviewSurvey($surveyId) + { + if ( !isset($_SESSION['loginID'], $_SESSION['USER_RIGHT_SUPERADMIN']) ) + return false; + + $rightresult = db_execute_assoc( + "SELECT uid + FROM ".($this->db->dbprefix('survey_permissions'))." + WHERE sid = '".$this->db->escape($surveyId)."' + AND uid = '".$this->db->escape($_SESSION['loginID'])."' + GROUP BY uid"); + if ($rightresult->num_rows() > 0 || $_SESSION['USER_RIGHT_SUPERADMIN'] == 1) + { + return true; + } + return false; + } + + function _killPage(&$redata, $iDebugLine, $sTemplateDir = null, $bKillSession = false) + { + if ( $sTemplateDir == null ) + $sTemplateDir = $this->config->item("standardtemplaterootdir"); + + $this->_printTemplateContent($sTemplateDir.'/default/endpage.pstpl', $redata, $iDebugLine); + doFooter(); + if ( $bKillSession ) + killSession(); + exit; + } + + function _createNewUserSessionAndRedirect($surveyId, &$redata, $asMessage = array()) + { + $baselang = GetBaseLanguageFromSurveyID($surveyId); + $this->load->library('Limesurvey_lang',array("langcode"=>$baselang)); + $clang = $this->limesurvey_lang; + // Let's first regenerate a session id + killSession(); + // Let's redirect the client to the same URL after having reseted the session + //header("Location: $rooturl/index.php?" .$_SERVER['QUERY_STRING']); + sendcacheheaders(); + doHeader(); + + $template = $this->config->item("standardtemplaterootdir").'/default/startpage.pstpl'; + $this->_printTemplateContent($template, $redata, __LINE__); + + $this->_printMessage($asMessage); + + $this->_killPage($redata, __LINE__); + } + + function _printMessage($asLines) + { + if ( func_num_args() > 1 ) + $asLines = func_get_args(); + + if ( size($asLines) == 0 ) + return; + + $sError = array_shift($asLines); + + echo "\t
    \n"; + echo "\t

    \n"; + if ( $sError != null ) + { + echo "\t".$sError."

    \n"; + } + echo "\t".implode ("

    \n\t", $asLines)."

    \n"; + echo "\t

    \n"; + echo "\t
    \n"; + } + + function _printTemplateContent($sTemplateFile, &$redata, $iDebugLine = -1) + { + echo templatereplace(file_get_contents($sTemplateFile),array(),$redata,'survey['.$iDebugLine.']'); + } } -/* End of file welcome.php */ -/* Location: ./application/controllers/welcome.php */ \ No newline at end of file +/* End of file survey.php */ +/* Location: ./application/controllers/survey.php */ \ No newline at end of file diff --git a/application/helpers/replacements_helper.php b/application/helpers/replacements_helper.php index bd87a263349..1fae9fe12a9 100644 --- a/application/helpers/replacements_helper.php +++ b/application/helpers/replacements_helper.php @@ -60,7 +60,7 @@ function templatereplace($line, $replacements=array(),&$redata=array(), $debugSr 'thissurvey', 'token', 'totalBoilerplatequestions', - 'totalquestions ', + 'totalquestions', ); $varsPassed = array(); diff --git a/application/libraries/Group_format.php b/application/libraries/Group_format.php index 12bee4fce93..5baab7703a2 100644 --- a/application/libraries/Group_format.php +++ b/application/libraries/Group_format.php @@ -14,11 +14,11 @@ */ class Group_format { - + function run($args) { - + global $surveyid, $thissurvey, $totalquestions, $token; - + extract($args); @@ -29,8 +29,8 @@ function run($args) { $_POST = $CI->input->post(); $allowmandbackwards = $CI->config->item("allowmandbackwards"); - - + + //Security Checked: POST, GET, SESSION, REQUEST, returnglobal, DB $previewgrp = false; if (isset($param['action']) && ($param['action']=='previewgroup')){ @@ -40,7 +40,7 @@ function run($args) { if ($param['newtest']=="Y") setcookie("limesurvey_timers", "0"); $show_empty_group = false; - + if ($previewgrp) { $totalquestions = buildsurveysession($surveyid); @@ -59,14 +59,14 @@ function run($args) { if(isset($thissurvey['showwelcome']) && $thissurvey['showwelcome'] == 'N') { //If explicitply set, hide the welcome screen $_SESSION['step'] = 1; - } + } } - + if (!isset($_SESSION['totalsteps'])) {$_SESSION['totalsteps']=0;} if (!isset($_SESSION['maxstep'])) {$_SESSION['maxstep']=0;} if (!isset($gl)) {$gl=array('null');} $_SESSION['prevstep']=$_SESSION['step']; - + //Move current step ########################################################################### if (isset($move) && $move == 'moveprev' && ($thissurvey['allowprev']=='Y' || $thissurvey['allowjumps']=='Y')) { @@ -83,18 +83,18 @@ function run($args) { if ($move > 0 && (($move <= $_SESSION['step']) || (isset($_SESSION['maxstep']) && $move <= $_SESSION['maxstep']))) $_SESSION['step'] = $move; } - + // We do not keep the participant session anymore when the same browser is used to answer a second time a survey (let's think of a library PC for instance). // Previously we used to keep the session and redirect the user to the // submit page. //if (isset($_SESSION['finished'])) {$move='movesubmit'; } - + if ($_SESSION['step'] == 0) { display_first_page(); exit; } - - + + //CHECK IF ALL MANDATORY QUESTIONS HAVE BEEN ANSWERED ############################################ //First, see if we are moving backwards or doing a Save so far, and its OK not to check: if ($allowmandbackwards==1 && ( @@ -107,24 +107,24 @@ function run($args) { { $backok="N"; } - + //Now, we check mandatory questions if necessary //CHECK IF ALL CONDITIONAL MANDATORY QUESTIONS THAT APPLY HAVE BEEN ANSWERED // TODO - Modify this to ensure that irrelevant mandatories are not required $notanswered=addtoarray_single(checkmandatorys($move,$backok),checkconditionalmandatorys($move,$backok)); - + //CHECK INPUT $notvalidated=aCheckInput($surveyid, $move, $backok); - + // CHECK UPLOADED FILES $filenotvalidated = checkUploadedFileValidity($surveyid, $move, $backok); - + //SEE IF THIS GROUP SHOULD DISPLAY $show_empty_group = false; - + if ($_SESSION['step']==0) $show_empty_group = true; - + if (isset($move) && $_SESSION['step'] != 0 && $move != "movesubmit") { while(isset($_SESSION['grouplist'][$_SESSION['step']-1]) && checkgroupfordisplay($_SESSION['grouplist'][$_SESSION['step']-1][0],($thissurvey['anonymized']!='N'),$thissurvey['sid']) === false) @@ -144,7 +144,7 @@ function run($args) { // or create an empty page giving the user the explicit option to submit. if (isset($show_empty_group_if_the_last_group_is_hidden) && $show_empty_group_if_the_last_group_is_hidden == true) { - + $show_empty_group = true; break; } else @@ -156,7 +156,7 @@ function run($args) { } } } - + //SUBMIT ############################################################################### if ((isset($move) && $move == "movesubmit") && (!isset($notanswered) || !$notanswered) && (!isset($notvalidated) || !$notvalidated ) && (!isset($filenotvalidated) || !$filenotvalidated)) { @@ -168,7 +168,7 @@ function run($args) { $_SESSION['insertarray'][] = "refurl"; } } - + //COMMIT CHANGES TO DATABASE if ($thissurvey['active'] != "Y") //If survey is not active, don't really commit { @@ -181,19 +181,19 @@ function run($args) { { killSession(); } - + sendcacheheaders(); doHeader(); $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Group_format[189]'); - + //Check for assessments if ($thissurvey['assessments']== "Y" && $assessments) { echo templatereplace(file_get_contents("$thistpl/assessment.pstpl"),array(),$redata,'Group_format[194]'); } - + // fetch all filenames from $_SESSIONS['files'] and delete them all // from the /upload/tmp/ directory /*echo "
    ";print_r($_SESSION);echo "
    "; @@ -219,7 +219,7 @@ function run($args) { $cookiename="PHPSID".returnglobal('sid')."STATUS"; setcookie("$cookiename", "COMPLETE", time() + 31536000); //Cookie will expire in 365 days } - + //Before doing the "templatereplace()" function, check the $thissurvey['url'] //field for limereplace stuff, and do transformations! $thissurvey['surveyls_url']=dTexts::run($thissurvey['surveyls_url']); @@ -228,7 +228,7 @@ function run($args) { $redata = compact(array_keys(get_defined_vars())); $content=''; $content .= templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Group_format[230]'); - + //Check for assessments if ($thissurvey['assessments']== "Y") { @@ -239,22 +239,22 @@ function run($args) { $content .= templatereplace(file_get_contents("$thistpl/assessment.pstpl"),array(),$redata,'Group_format[238]'); } } - + //Update the token if needed and send a confirmation email if (isset($clienttoken) && $clienttoken) { submittokens(); } - + //Send notifications - + SendSubmitNotifications(); - + $redata = compact(array_keys(get_defined_vars())); $content=''; $content .= templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Group_format[255]'); - + //echo $thissurvey['url']; //Check for assessments if ($thissurvey['assessments']== "Y") @@ -266,8 +266,8 @@ function run($args) { $content .= templatereplace(file_get_contents("$thistpl/assessment.pstpl"),array(),$redata,'Group_format[266]'); } } - - + + if (trim(strip_tags($thissurvey['surveyls_endtext']))=='') { $completed = "
    ".$clang->gT("Thank you!")."

    \n\n" @@ -277,7 +277,7 @@ function run($args) { { $completed = $thissurvey['surveyls_endtext']; } - + // Link to Print Answer Preview ********** if ($thissurvey['printanswers']=='Y') { @@ -287,9 +287,9 @@ function run($args) { ."
    \n"; } //***************************************** - + if ($thissurvey['publicstatistics']=='Y' && $thissurvey['printanswers']=='Y') {$completed .='
    '.$clang->gT("or");} - + // Link to Public statistics ********** if ($thissurvey['publicstatistics']=='Y') { @@ -299,10 +299,10 @@ function run($args) { ."
    \n"; } //***************************************** - + $_SESSION['finished']=true; $_SESSION['sid']=$surveyid; - + sendcacheheaders(); //Automatically redirect the page to the "url" setting for the survey @@ -315,20 +315,20 @@ function run($args) { $url=str_replace("{TOKEN}",$clienttoken, $url); // to activate the TOKEN in the END URL $url=str_replace("{SID}", $surveyid, $url); // to activate the SID in the END URL $url=str_replace("{LANG}", $clang->getlangcode(), $url); // to activate the LANG in the END URL - + header("Location: {$url}"); } - - + + //if($thissurvey['printanswers'] != 'Y' && $thissurvey['usecookie'] != 'Y' && $tokensexist !=1) if($thissurvey['printanswers'] != 'Y') { killSession(); } - + doHeader(); echo $content; - + } $redata = compact(array_keys(get_defined_vars())); @@ -341,7 +341,7 @@ function run($args) { } //SEE IF $surveyid EXISTS #################################################################### - if ($surveyexists <1) + if ($surveyExists <1) { //SURVEY DOES NOT EXIST. POLITELY EXIT. $redata = compact(array_keys(get_defined_vars())); @@ -352,14 +352,14 @@ function run($args) { doFooter(); exit; } - + //GET GROUP DETAILS - + if ($previewgrp) { setcookie("limesurvey_timers", "0"); $_SESSION['step'] = $param['gid']+1; - + foreach($_SESSION['grouplist'] as $index=>$group) { if ($group[0]==$param['gid']){ @@ -367,7 +367,7 @@ function run($args) { break; } } - + $gid=$_SESSION['grouplist'][$grouparrayno][0]; $groupname=$_SESSION['grouplist'][$grouparrayno][1]; $groupdescription=$_SESSION['grouplist'][$grouparrayno][2]; @@ -388,21 +388,21 @@ function run($args) { $groupdescription=$_SESSION['grouplist'][$grouparrayno][2]; } } - + //Setup an inverted fieldnamesInfo for quick lookup of field answers. $aFieldnamesInfoInv = aArrayInvert($_SESSION['fieldnamesInfo']); if ($_SESSION['step'] > $_SESSION['maxstep']) { $_SESSION['maxstep'] = $_SESSION['step']; } - + //****************************************************************************************************** //PRESENT SURVEY //****************************************************************************************************** - - - - + + + + //require_once("qanda.php"); //This should be qanda.php when finished $CI->load->helper("qanda"); setNoAnswerMode($thissurvey); @@ -413,26 +413,26 @@ function run($args) { $conmandatoryfns=array(); $conditions=array(); $inputnames=array(); - + $qtypesarray = array(); - + $qnumber = 0; //This re-starts the group, after checking relevance, so get consistent and unduplcated set of replacement functions LimeExpressionManager::StartProcessingPage(); LimeExpressionManager::StartProcessingGroup($gid,($thissurvey['anonymized']!="N"),$thissurvey['sid']); - + foreach ($_SESSION['fieldarray'] as $key=>$ia) { $qtypesarray[$ia[1]] = $ia[4]; ++$qnumber; $ia[9] = $qnumber; // incremental question count; - + if ((isset($ia[10]) && $ia[10] == $gid) || (!isset($ia[10]) && $ia[5] == $gid)) { if(IsSet($hideQuestion[$ia[0]]) && $hideQuestion[$ia[0]]==true){ continue; } - + $qidattributes=getQuestionAttributeValues($ia[0]); if ($ia[4] != '*' && ($qidattributes===false || $qidattributes['hidden']==1)) { // Should we really skip the question here, maybe the result won't be stored if we do that @@ -443,7 +443,7 @@ function run($args) { // It prevents further calls to checkquestionfordisplay if using PREVIOUS button // from the LimeSurvey Navigator Toolbar // $_SESSION['fieldarray'][$key][7]='N'; - + //Get the answers/inputnames list($plus_qanda, $plus_inputnames)=retrieveAnswers($ia); if ($plus_qanda) @@ -456,25 +456,25 @@ function run($args) { { $inputnames = addtoarray_single($inputnames, $plus_inputnames); } - + //Display the "mandatory" popup if necessary if (isset($notanswered)) { list($mandatorypopup, $popup)=mandatory_popup($ia, $notanswered); } - + //Display the "validation" popup if necessary if (isset($notvalidated)) { list($validationpopup, $vpopup)=validation_popup($ia, $notvalidated); } - + // Display the "file validation" popup if necessary if (isset($filenotvalidated)) { list($filevalidationpopup, $fpopup) = file_validation_popup($ia, $filenotvalidated); } - + //Get list of mandatory questions list($plusman, $pluscon)=create_mandatorylist($ia); if ($plusman !== null) @@ -489,7 +489,7 @@ function run($args) { $conmandatorys=addtoarray_single($conmandatorys, $plus_conman); $conmandatoryfns=addtoarray_single($conmandatoryfns, $plus_conmanfns); } - + //Build an array containing the conditions that apply for this page $plus_conditions=retrieveConditionInfo($ia); //Returns false if no conditions if ($plus_conditions) @@ -500,7 +500,7 @@ function run($args) { if ($ia[4] == "|") $upload_file = TRUE; } //end iteration - + if (isset($thissurvey['showprogress']) && $thissurvey['showprogress'] == 'Y') { if ($show_empty_group) @@ -513,22 +513,22 @@ function run($args) { } } $languagechanger = makelanguagechanger(); - + //READ TEMPLATES, INSERT DATA AND PRESENT PAGE sendcacheheaders(); doHeader(); - + if (isset($popup)) {echo $popup;} if (isset($vpopup)) {echo $vpopup;} if (isset($fpopup)) {echo $fpopup;} - + //foreach(file("$thistpl/startpage.pstpl") as $op) //{ // echo templatereplace($op); //} $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Group_format[530]'); - + //ALTER PAGE CLASS TO PROVIDE WHOLE-PAGE ALTERNATION if ($_SESSION['step'] != $_SESSION['prevstep'] || (isset($_SESSION['stepno']) && $_SESSION['stepno'] % 2)) @@ -542,9 +542,9 @@ function run($args) { . "\n"; } } - + $hiddenfieldnames=implode("|", $inputnames); - + if (isset($upload_file) && $upload_file) echo "
    @@ -555,18 +555,18 @@ function run($args) { \n"; echo sDefaultSubmitHandler(); // <-- END FEATURE - SAVE - + // <-- START THE SURVEY --> $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/survey.pstpl"),array(),$redata,'Group_format[561]'); - + // the runonce element has been changed from a hidden to a text/display:none one // in order to workaround an not-reproduced issue #4453 (lemeur) echo " \n"; } } - + echo "\n\n"; echo sDefaultSubmitHandler(); @@ -501,7 +501,7 @@ function run($args) { echo "' id='fieldnames' />\n"; echo "\n\n\n"; echo templatereplace(file_get_contents("$thistpl/survey.pstpl"),array(),$redata,'Question_format[503]'); - + if ($bIsGroupDescrPage) { $presentinggroupdescription = "yes"; @@ -509,13 +509,13 @@ function run($args) { echo "\t\n"; echo templatereplace(file_get_contents("$thistpl/startgroup.pstpl"),array(),$redata,'Question_format[510]'); echo "\n"; - + //if ($groupdescription) //{ echo templatereplace(file_get_contents("$thistpl/groupdescription.pstpl"),array(),$redata,'Question_format[515]'); //} echo "\n"; - + echo "\n\n\n"; echo "\t\n\n"; - + //Display the "mandatory" message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($notanswered) && $notanswered == true) { echo "

    " . $clang->gT("One or more mandatory questions have not been answered. You cannot proceed until these have been completed.") . "

    "; } - + //Display the "validation" message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($notvalidated) && $notvalidated == true) { echo "

    " . $clang->gT("One or more questions have not been answered in a valid manner. You cannot proceed until these answers are valid.") . "

    "; } - + // Display the File Validation message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($filenotvalidated) && $filenotvalidated == true) { echo "

    ". $clang->gT("One or more uploaded files do not satisfy the criteria") . "

    "; } - - + + echo "\n\n\n"; if (is_array($qanda)) { @@ -581,7 +581,7 @@ function run($args) { { echo "\n"; $q_class = question_class($qa[8]); // render question class (see common.php) - + if ($qa[9] == 'Y') { $man_class = ' mandatory'; @@ -590,7 +590,7 @@ function run($args) { { $man_class = ''; } - + // Fixed by lemeur: can't rely on javascript checkconditions with // question-by-question display to hide/show conditionnal questions // as conditions are evaluated with php code @@ -599,7 +599,7 @@ function run($args) { // condition eval in php) // if ($qa[3] != 'Y') {$n_q_display = '';} else { $n_q_display = ' style="display: none;"';} if ($conditionforthisquestion != 'Y') {$n_q_display = '';} else { $n_q_display = ' style="display: none;"';} - + $question= $qa[0]; //=================================================================== // The following four variables offer the templating system the @@ -613,7 +613,7 @@ function run($args) { //=================================================================== $answer=$qa[1]; $help=$qa[2]; - + $question_template = file_get_contents($thistpl.'/question.pstpl'); $redata = compact(array_keys(get_defined_vars())); @@ -645,27 +645,27 @@ function run($args) { LimeExpressionManager::FinishProcessingGroup(); LimeExpressionManager::FinishProcessingPage(); echo LimeExpressionManager::GetRelevanceAndTailoringJavaScript(); - + $navigator = surveymover(); $redata = compact(array_keys(get_defined_vars())); echo "\n\n\n"; echo templatereplace(file_get_contents("$thistpl/navigator.pstpl"),array(),$redata,'Question_format[653]'); echo "\n"; - + if ($thissurvey['active'] != "Y") { echo "

    ".$clang->gT("This survey is currently not active. You will not be able to save your responses.")."

    \n"; } - + echo "\n"; - + if($thissurvey['allowjumps']=='Y' && !$bIsGroupDescrPage) { echo "\n\n\n"; - + $iLastGrp = null; - + echo '

    ' . $clang->gT("Question index") . '

    '; for($v = 0, $n = 0; $n != $_SESSION['maxstep']; ++$n) { @@ -673,10 +673,10 @@ function run($args) { $qidattributes=getQuestionAttributeValues($ia[0], $ia[4]); if($qidattributes['hidden']==1 || !checkquestionfordisplay($ia[0])) continue; - + $sText = FlattenText($ia[3]); $bAnsw = bCheckQuestionForAnswer($ia[1], $aFieldnamesInfoInv); - + if($iLastGrp != $ia[5]) { $iLastGrp = $ia[5]; @@ -689,25 +689,25 @@ function run($args) { } } } - + ++$v; - + $class = ($n == $_SESSION['step'] - 1? 'current': ($bAnsw? 'answer': 'missing')); if($v % 2) $class .= " odd"; - + $s = $n + 1; echo "
    $v$sText
    "; } - + if($_SESSION['maxstep'] == $_SESSION['totalsteps']) { echo "\n"; } - + echo '
    '; } - + if (isset($conditions) && is_array($conditions) && count($conditions) != 0) { //if conditions exist, create hidden inputs for 'previously' answered questions @@ -721,8 +721,8 @@ function run($args) { } } } - - + + //SOME STUFF FOR MANDATORY QUESTIONS if (remove_nulls_from_array($mandatorys) && $newgroup != "Y") { @@ -744,10 +744,10 @@ function run($args) { $conmandatoryfn=implode("|", remove_nulls_from_array($conmandatoryfns)); echo "\n"; } - + echo "\n"; echo "\n"; - echo "\n"; + echo "\n"; if(!isset($token)) $token = ""; echo "\n"; echo "\n"; @@ -759,7 +759,7 @@ function run($args) { $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'Question_format[760]'); doFooter(); - + } function _checkIfNewGroup($ia) diff --git a/application/libraries/Survey_format.php b/application/libraries/Survey_format.php index 0b701db4227..a0a1c2f275d 100644 --- a/application/libraries/Survey_format.php +++ b/application/libraries/Survey_format.php @@ -14,18 +14,18 @@ */ class Survey_format { - + function run($args) { - + global $thissurvey, $token; - + extract($args); $CI =& get_instance(); //$_SESSION = $CI->session->userdata; $dbprefix = $CI->db->dbprefix; $publicurl = base_url(); - - + + //Security Checked: POST, GET, SESSION, REQUEST, returnglobal, DB //Move current step ########################################################################### @@ -33,23 +33,23 @@ function run($args) { if (!isset($_SESSION['totalsteps'])) {$_SESSION['totalsteps']=0;} if (isset($move) && $move == "moveprev") {$_SESSION['step'] = $thisstep-1;} if (isset($move) && $move == "movenext") {$_SESSION['step'] = $thisstep+1;} - + // We do not keep the participant session anymore when the same browser is used to answer a second time a survey (let's think of a library PC for instance). // Previously we used to keep the session and redirect the user to the // submit page. //if (isset($_SESSION['finished'])) {$move="movesubmit"; } - + // TODO - also check relevance //CHECK IF ALL MANDATORY QUESTIONS HAVE BEEN ANSWERED ############################################ //CHECK IF ALL CONDITIONAL MANDATORY QUESTIONS THAT APPLY HAVE BEEN ANSWERED $notanswered=addtoarray_single(checkmandatorys($move),checkconditionalmandatorys($move)); - + //CHECK INPUT $notvalidated=aCheckInput($surveyid, $move); - + //CHECK UPLOADED FILES $filenotvalidated = checkUploadedFileValidity($surveyid, $move); - + //SUBMIT $redata = compact(array_keys(get_defined_vars())); if ((isset($move) && $move == "movesubmit") && (!isset($notanswered) || !$notanswered) && (!isset($notvalidated) && !$notvalidated) && (!isset($filenotvalidated) || !$filenotvalidated)) @@ -66,7 +66,7 @@ function run($args) { $_SESSION['insertarray'][] = "refurl"; } } - + //COMMIT CHANGES TO DATABASE if ($thissurvey['active'] != "Y") { @@ -74,24 +74,24 @@ function run($args) { { $assessments = doAssessment($surveyid); // assessments are using session data so this has to be placed before killSession } - + //Before doing the "templatereplace()" function, check the $thissurvey['url'] //field for limereplace stuff, and do transformations! - + killSession(); sendcacheheaders(); doHeader(); $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Survey_format[86]'); - + //Check for assessments - + if ($thissurvey['assessments']== "Y" && $assessments) { echo templatereplace(file_get_contents("$thistpl/assessment.pstpl"),array(),$redata,'Survey_format[92]'); } - + $completed = $thissurvey['surveyls_endtext']; $completed .= "
    ".$clang->gT("Did Not Save")."

    \n\n" . $clang->gT("Your survey responses have not been recorded. This survey is not yet active.")."

    \n"; @@ -109,7 +109,7 @@ function run($args) { $cookiename="PHPSID".returnglobal('sid')."STATUS"; setcookie("$cookiename", "COMPLETE", time() + 31536000); //Cookie will expire in 365 days } - + //Before doing the "templatereplace()" function, check the $thissurvey['url'] //field for limereplace stuff, and do transformations! $thissurvey['surveyls_url']=dTexts::run($thissurvey['surveyls_url']); @@ -121,15 +121,15 @@ function run($args) { $redata = compact(array_keys(get_defined_vars())); $content=''; $content .= templatereplace(file_get_contents("$thistpl/startpage.pstpl"),array(),$redata,'Survey_format[123]'); - + if ($assessments) { $content .= templatereplace(file_get_contents("$thistpl/assessment.pstpl"),array(),$redata,'Survey_format[127]'); } - + // Unsetting $postedfieldnames tells the createinsertquery() function only to set the sbumit date, nothing else unset($postedfieldnames); - + // only update submitdate if the user did not already visit the submit page if (!isset($_SESSION['finished'])) { @@ -137,8 +137,8 @@ function run($args) { // $connect->Execute($subquery); // Checked $CI->save->submitanswer($surveyid, $thissurvey, $move); } - - + + //Survey end text if (trim(strip_tags($thissurvey['surveyls_endtext']))=='') { @@ -149,7 +149,7 @@ function run($args) { { $completed = $thissurvey['surveyls_endtext']; } - + // Link to Print Answer Preview ********** if ($thissurvey['printanswers']=='Y') { @@ -159,9 +159,9 @@ function run($args) { ."
    \n"; } //***************************************** - + if ($thissurvey['publicstatistics']=='Y' && $thissurvey['printanswers']=='Y') {$completed .='
    '.$clang->gT("or");} - + // Link to Public statistics ********** if ($thissurvey['publicstatistics']=='Y') { @@ -171,23 +171,23 @@ function run($args) { ."
    \n"; } //***************************************** - + //Update the token if needed and send a confirmation email if (isset($clienttoken) && $clienttoken) { submittokens(); } - - //Send notification to survey administrator + + //Send notification to survey administrator SendSubmitNotifications(); - + $_SESSION['finished']=true; $_SESSION['sid']=$surveyid; - + sendcacheheaders(); if (isset($thissurvey['autoredirect']) && $thissurvey['autoredirect'] == "Y" && $thissurvey['surveyls_url']) { - + $url = dTexts::run($thissurvey['surveyls_url']); $url = passthruReplace($url, $thissurvey); $url=str_replace("{SAVEDID}",$saved_id, $url); // to activate the SAVEDID in the END URL @@ -196,10 +196,10 @@ function run($args) { $url=str_replace("{LANG}", $clang->getlangcode(), $url); // to activate the LANG in the END URL //Automatically redirect the page to the "url" setting for the survey session_write_close(); - + header("Location: {$url}"); } - + //if($thissurvey['printanswers'] != 'Y' && $thissurvey['usecookie'] != 'Y' && $tokensexist !=1) if($thissurvey['printanswers'] != 'Y') { @@ -207,20 +207,20 @@ function run($args) { } doHeader(); echo $content; - + } $redata = compact(array_keys(get_defined_vars())); echo templatereplace(file_get_contents("$thistpl/completed.pstpl"),array(),$redata,'Survey_format[213]'); - + echo "\n
    \n"; echo templatereplace(file_get_contents("$thistpl/endpage.pstpl"),array(),$redata,'Survey_format[216]'); doFooter(); exit; } - + //SEE IF $surveyid EXISTS - if ($surveyexists <1) + if ($surveyExists <1) { sendcacheheaders(); doHeader(); @@ -234,14 +234,14 @@ function run($args) { doFooter(); exit; } - + //RUN THIS IF THIS IS THE FIRST TIME if ((!isset($_SESSION['step']) || !$_SESSION['step'] || !isset($totalquestions)) && (!isset($notanswered) || !$notanswered) && (!isset($notvalidated) && !$notvalidated) && (!isset($filenotvalidated) || !$filenotvalidated)) { $totalquestions = buildsurveysession($surveyid); $_SESSION['step'] = 1; } - + // If the survey uses answer persistence and a srid is registered in SESSION // then loadanswers from this srid if ($thissurvey['tokenanswerspersistence'] == 'Y' && @@ -251,11 +251,11 @@ function run($args) { { loadanswers(); } - + //****************************************************************************************************** //PRESENT SURVEY //****************************************************************************************************** - + //GET GROUP DETAILS //require_once("qanda.php"); $CI->load->helper("qanda"); @@ -306,23 +306,23 @@ function run($args) { { $inputnames = addtoarray_single($inputnames, $plus_inputnames); } - + //Display the "mandatory" popup if necessary if (isset($notanswered)) { list($mandatorypopup, $popup)=mandatory_popup($ia, $notanswered); } - + if (isset($notvalidated)) { list($validationpopup, $vpopup)=validation_popup($ia, $notvalidated); } - + if (isset($filenotvalidated)) { list($filevalidationpopup, $fpopup) = file_validation_popup($ia, $filenotvalidated); } - + //Get list of mandatory questions list($plusman, $pluscon)=create_mandatorylist($ia); if ($plusman !== null) @@ -337,7 +337,7 @@ function run($args) { $conmandatorys=addtoarray_single($conmandatorys, $plus_conman); $conmandatoryfns=addtoarray_single($conmandatoryfns, $plus_conmanfns); } - + //Build an array containing the conditions that apply for this page $plus_conditions=retrieveConditionInfo($ia); //Returns false if no conditions if ($plus_conditions) @@ -352,7 +352,7 @@ function run($args) { } LimeExpressionManager::FinishProcessingGroup(); } - + //READ TEMPLATES, INSERT DATA AND PRESENT PAGE sendcacheheaders(); doHeader(); @@ -367,26 +367,26 @@ function run($args) { .implode("|", $inputnames) ."' />\n"; echo sDefaultSubmitHandler(); - + // <-- END FEATURE - SAVE - + if(isset($thissurvey['showwelcome']) && $thissurvey['showwelcome'] == 'N') { //Hide the welcome screen if explicitly set } else { echo templatereplace(file_get_contents("$thistpl/welcome.pstpl"),array(),$redata,'Survey_format[376]')."\n"; } - + if ($thissurvey['anonymized'] == "Y") { echo templatereplace(file_get_contents("$thistpl/privacy.pstpl"),array(),$redata,'Survey_format[381]')."\n"; } - + print << \n\n"; // End checkconditions javascript function - + //Display the "mandatory" message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($notanswered) && $notanswered == true) { echo "

    " . $clang->gT("One or more mandatory questions have not been answered. You cannot proceed until these have been completed.") . "

    "; } - + //Display the "validation" message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($notvalidated) && $notvalidated == true) { echo "

    " . $clang->gT("One or more questions have not been answered in a valid manner. You cannot proceed until these answers are valid.") . "

    "; } - + //Display the "file validation" message on page if necessary if (isset($showpopups) && $showpopups == 0 && isset($filenotvalidated) && $filenotvalidated == true) { echo "

    " . $clang->gT("One or more files are either not in the proper format or exceed the maximum file size limitation. You cannot proceed until these answers are valid.") . "

    "; } - + foreach ($_SESSION['grouplist'] as $gl) { $gid=$gl[0]; @@ -982,13 +982,13 @@ function checkconditions(value, name, type) echo "\n"; LimeExpressionManager::StartProcessingGroup($gid,($thissurvey['anonymized']!="N"),$thissurvey['sid']); - + if ($groupdescription) { echo templatereplace(file_get_contents("$thistpl/groupdescription.pstpl"),array(),$redata,'Survey_format[988]'); } echo "\n"; - + // count the number of non-conditionnal and conditionnal questions in this group echo "\n\n\n"; if (is_array($qanda)) @@ -998,7 +998,7 @@ function checkconditions(value, name, type) if ($gl[0] == $qa[6]) { $q_class = question_class($qa[8]); // render question class (see common.php) - + if ($qa[9] == 'Y') { $man_class = ' mandatory'; @@ -1007,7 +1007,7 @@ function checkconditions(value, name, type) { $man_class = ''; } - + if ($qa[3] != 'Y') { $n_q_display = ''; @@ -1016,7 +1016,7 @@ function checkconditions(value, name, type) { $n_q_display = ' style="display: none;"'; } - + $question= $qa[0]; //=================================================================== // The following four variables offer the templating system the @@ -1030,7 +1030,7 @@ function checkconditions(value, name, type) //=================================================================== $answer=$qa[1]; $help=$qa[2]; - + $question_template = file_get_contents($thistpl.'/question.pstpl'); $redata = compact(array_keys(get_defined_vars())); @@ -1039,7 +1039,7 @@ function checkconditions(value, name, type) // if {QUESTION_ESSENTIALS} is present in the template but not {QUESTION_CLASS} remove it because you don't want id="" and display="" duplicated. $question_template = str_replace( '{QUESTION_ESSENTIALS}' , '' , $question_template ); $question_template = str_replace( '{QUESTION_CLASS}' , '' , $question_template ); - + echo '
    @@ -1058,14 +1058,14 @@ function checkconditions(value, name, type) } $redata = compact(array_keys(get_defined_vars())); echo "\n\n\n"; - + echo templatereplace(file_get_contents("$thistpl/endgroup.pstpl"),array(),$redata,'Survey_format[1062]s'); echo "\n\n
    \n"; echo "\n"; LimeExpressionManager::FinishProcessingGroup(); } - + //echo " \n"; $navigator = surveymover(); @@ -1073,10 +1073,10 @@ function checkconditions(value, name, type) echo "\n\n\n"; echo templatereplace(file_get_contents("$thistpl/navigator.pstpl"),array(),$redata,'Survey_format[1074]'); echo "\n"; - + if ($thissurvey['active'] != "Y") {echo "

    ".$clang->gT("This survey is currently not active. You will not be able to save your responses.")."

    \n";} - - + + if (is_array($conditions) && count($conditions) != 0 ) { //if conditions exist, create hidden inputs for 'previously' answered questions @@ -1115,7 +1115,7 @@ function checkconditions(value, name, type) LimeExpressionManager::FinishProcessingPage(); echo LimeExpressionManager::GetRelevanceAndTailoringJavaScript(); - + echo "\n" ."\n" ."\n" diff --git a/application/libraries/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE b/application/libraries/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE new file mode 100644 index 00000000000..a65e83e8762 --- /dev/null +++ b/application/libraries/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE @@ -0,0 +1,399 @@ +Simple Test interface changes +============================= +Because the SimpleTest tool set is still evolving it is likely that tests +written with earlier versions will fail with the newest ones. The most +dramatic changes are in the alpha releases. Here is a list of possible +problems and their fixes... + +assertText() no longer finds a string inside a ', 'js'); + $this->mapHandler('comment', 'ignore'); + $this->addEntryPattern('', 'comment'); + } + + /** + * Pattern matches to start and end a tag. + * @param string $tag Name of tag to scan for. + * @access private + */ + protected function addTag($tag) { + $this->addSpecialPattern("", 'text', 'acceptEndToken'); + $this->addEntryPattern("<$tag", 'text', 'tag'); + } + + /** + * Pattern matches to parse the inside of a tag + * including the attributes and their quoting. + * @access private + */ + protected function addInTagTokens() { + $this->mapHandler('tag', 'acceptStartToken'); + $this->addSpecialPattern('\s+', 'tag', 'ignore'); + $this->addAttributeTokens(); + $this->addExitPattern('/>', 'tag'); + $this->addExitPattern('>', 'tag'); + } + + /** + * Matches attributes that are either single quoted, + * double quoted or unquoted. + * @access private + */ + protected function addAttributeTokens() { + $this->mapHandler('dq_attribute', 'acceptAttributeToken'); + $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute'); + $this->addPattern("\\\\\"", 'dq_attribute'); + $this->addExitPattern('"', 'dq_attribute'); + $this->mapHandler('sq_attribute', 'acceptAttributeToken'); + $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute'); + $this->addPattern("\\\\'", 'sq_attribute'); + $this->addExitPattern("'", 'sq_attribute'); + $this->mapHandler('uq_attribute', 'acceptAttributeToken'); + $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute'); + } +} + +/** + * Converts HTML tokens into selected SAX events. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleHtmlSaxParser { + private $lexer; + private $listener; + private $tag; + private $attributes; + private $current_attribute; + + /** + * Sets the listener. + * @param SimplePhpPageBuilder $listener SAX event handler. + * @access public + */ + function __construct($listener) { + $this->listener = $listener; + $this->lexer = $this->createLexer($this); + $this->tag = ''; + $this->attributes = array(); + $this->current_attribute = ''; + } + + /** + * Runs the content through the lexer which + * should call back to the acceptors. + * @param string $raw Page text to parse. + * @return boolean False if parse error. + * @access public + */ + function parse($raw) { + return $this->lexer->parse($raw); + } + + /** + * Sets up the matching lexer. Starts in 'text' mode. + * @param SimpleSaxParser $parser Event generator, usually $self. + * @return SimpleLexer Lexer suitable for this parser. + * @access public + */ + static function createLexer(&$parser) { + return new SimpleHtmlLexer($parser); + } + + /** + * Accepts a token from the tag mode. If the + * starting element completes then the element + * is dispatched and the current attributes + * set back to empty. The element or attribute + * name is converted to lower case. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptStartToken($token, $event) { + if ($event == LEXER_ENTER) { + $this->tag = strtolower(substr($token, 1)); + return true; + } + if ($event == LEXER_EXIT) { + $success = $this->listener->startElement( + $this->tag, + $this->attributes); + $this->tag = ''; + $this->attributes = array(); + return $success; + } + if ($token != '=') { + $this->current_attribute = strtolower(html_entity_decode($token, ENT_QUOTES)); + $this->attributes[$this->current_attribute] = ''; + } + return true; + } + + /** + * Accepts a token from the end tag mode. + * The element name is converted to lower case. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptEndToken($token, $event) { + if (! preg_match('/<\/(.*)>/', $token, $matches)) { + return false; + } + return $this->listener->endElement(strtolower($matches[1])); + } + + /** + * Part of the tag data. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptAttributeToken($token, $event) { + if ($this->current_attribute) { + if ($event == LEXER_UNMATCHED) { + $this->attributes[$this->current_attribute] .= + html_entity_decode($token, ENT_QUOTES); + } + if ($event == LEXER_SPECIAL) { + $this->attributes[$this->current_attribute] .= + preg_replace('/^=\s*/' , '', html_entity_decode($token, ENT_QUOTES)); + } + } + return true; + } + + /** + * A character entity. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptEntityToken($token, $event) { + } + + /** + * Character data between tags regarded as + * important. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function acceptTextToken($token, $event) { + return $this->listener->addContent($token); + } + + /** + * Incoming data to be ignored. + * @param string $token Incoming characters. + * @param integer $event Lexer event type. + * @return boolean False if parse error. + * @access public + */ + function ignore($token, $event) { + return true; + } +} + +/** + * SAX event handler. Maintains a list of + * open tags and dispatches them as they close. + * @package SimpleTest + * @subpackage WebTester + */ +class SimplePhpPageBuilder { + private $tags; + private $page; + private $private_content_tag; + private $open_forms = array(); + private $complete_forms = array(); + private $frameset = false; + private $loading_frames = array(); + private $frameset_nesting_level = 0; + private $left_over_labels = array(); + + /** + * Frees up any references so as to allow the PHP garbage + * collection from unset() to work. + * @access public + */ + function free() { + unset($this->tags); + unset($this->page); + unset($this->private_content_tags); + $this->open_forms = array(); + $this->complete_forms = array(); + $this->frameset = false; + $this->loading_frames = array(); + $this->frameset_nesting_level = 0; + $this->left_over_labels = array(); + } + + /** + * This builder is always available. + * @return boolean Always true. + */ + function can() { + return true; + } + + /** + * Reads the raw content and send events + * into the page to be built. + * @param $response SimpleHttpResponse Fetched response. + * @return SimplePage Newly parsed page. + * @access public + */ + function parse($response) { + $this->tags = array(); + $this->page = $this->createPage($response); + $parser = $this->createParser($this); + $parser->parse($response->getContent()); + $this->acceptPageEnd(); + $page = $this->page; + $this->free(); + return $page; + } + + /** + * Creates an empty page. + * @return SimplePage New unparsed page. + * @access protected + */ + protected function createPage($response) { + return new SimplePage($response); + } + + /** + * Creates the parser used with the builder. + * @param SimplePhpPageBuilder $listener Target of parser. + * @return SimpleSaxParser Parser to generate + * events for the builder. + * @access protected + */ + protected function createParser(&$listener) { + return new SimpleHtmlSaxParser($listener); + } + + /** + * Start of element event. Opens a new tag. + * @param string $name Element name. + * @param hash $attributes Attributes without content + * are marked as true. + * @return boolean False on parse error. + * @access public + */ + function startElement($name, $attributes) { + $factory = new SimpleTagBuilder(); + $tag = $factory->createTag($name, $attributes); + if (! $tag) { + return true; + } + if ($tag->getTagName() == 'label') { + $this->acceptLabelStart($tag); + $this->openTag($tag); + return true; + } + if ($tag->getTagName() == 'form') { + $this->acceptFormStart($tag); + return true; + } + if ($tag->getTagName() == 'frameset') { + $this->acceptFramesetStart($tag); + return true; + } + if ($tag->getTagName() == 'frame') { + $this->acceptFrame($tag); + return true; + } + if ($tag->isPrivateContent() && ! isset($this->private_content_tag)) { + $this->private_content_tag = &$tag; + } + if ($tag->expectEndTag()) { + $this->openTag($tag); + return true; + } + $this->acceptTag($tag); + return true; + } + + /** + * End of element event. + * @param string $name Element name. + * @return boolean False on parse error. + * @access public + */ + function endElement($name) { + if ($name == 'label') { + $this->acceptLabelEnd(); + return true; + } + if ($name == 'form') { + $this->acceptFormEnd(); + return true; + } + if ($name == 'frameset') { + $this->acceptFramesetEnd(); + return true; + } + if ($this->hasNamedTagOnOpenTagStack($name)) { + $tag = array_pop($this->tags[$name]); + if ($tag->isPrivateContent() && $this->private_content_tag->getTagName() == $name) { + unset($this->private_content_tag); + } + $this->addContentTagToOpenTags($tag); + $this->acceptTag($tag); + return true; + } + return true; + } + + /** + * Test to see if there are any open tags awaiting + * closure that match the tag name. + * @param string $name Element name. + * @return boolean True if any are still open. + * @access private + */ + protected function hasNamedTagOnOpenTagStack($name) { + return isset($this->tags[$name]) && (count($this->tags[$name]) > 0); + } + + /** + * Unparsed, but relevant data. The data is added + * to every open tag. + * @param string $text May include unparsed tags. + * @return boolean False on parse error. + * @access public + */ + function addContent($text) { + if (isset($this->private_content_tag)) { + $this->private_content_tag->addContent($text); + } else { + $this->addContentToAllOpenTags($text); + } + return true; + } + + /** + * Any content fills all currently open tags unless it + * is part of an option tag. + * @param string $text May include unparsed tags. + * @access private + */ + protected function addContentToAllOpenTags($text) { + foreach (array_keys($this->tags) as $name) { + for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) { + $this->tags[$name][$i]->addContent($text); + } + } + } + + /** + * Parsed data in tag form. The parsed tag is added + * to every open tag. Used for adding options to select + * fields only. + * @param SimpleTag $tag Option tags only. + * @access private + */ + protected function addContentTagToOpenTags(&$tag) { + if ($tag->getTagName() != 'option') { + return; + } + foreach (array_keys($this->tags) as $name) { + for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) { + $this->tags[$name][$i]->addTag($tag); + } + } + } + + /** + * Opens a tag for receiving content. Multiple tags + * will be receiving input at the same time. + * @param SimpleTag $tag New content tag. + * @access private + */ + protected function openTag($tag) { + $name = $tag->getTagName(); + if (! in_array($name, array_keys($this->tags))) { + $this->tags[$name] = array(); + } + $this->tags[$name][] = $tag; + } + + /** + * Adds a tag to the page. + * @param SimpleTag $tag Tag to accept. + * @access public + */ + protected function acceptTag($tag) { + if ($tag->getTagName() == "a") { + $this->page->addLink($tag); + } elseif ($tag->getTagName() == "base") { + $this->page->setBase($tag->getAttribute('href')); + } elseif ($tag->getTagName() == "title") { + $this->page->setTitle($tag); + } elseif ($this->isFormElement($tag->getTagName())) { + for ($i = 0; $i < count($this->open_forms); $i++) { + $this->open_forms[$i]->addWidget($tag); + } + $this->last_widget = $tag; + } + } + + /** + * Opens a label for a described widget. + * @param SimpleFormTag $tag Tag to accept. + * @access public + */ + protected function acceptLabelStart($tag) { + $this->label = $tag; + unset($this->last_widget); + } + + /** + * Closes the most recently opened label. + * @access public + */ + protected function acceptLabelEnd() { + if (isset($this->label)) { + if (isset($this->last_widget)) { + $this->last_widget->setLabel($this->label->getText()); + unset($this->last_widget); + } else { + $this->left_over_labels[] = SimpleTestCompatibility::copy($this->label); + } + unset($this->label); + } + } + + /** + * Tests to see if a tag is a possible form + * element. + * @param string $name HTML element name. + * @return boolean True if form element. + * @access private + */ + protected function isFormElement($name) { + return in_array($name, array('input', 'button', 'textarea', 'select')); + } + + /** + * Opens a form. New widgets go here. + * @param SimpleFormTag $tag Tag to accept. + * @access public + */ + protected function acceptFormStart($tag) { + $this->open_forms[] = new SimpleForm($tag, $this->page); + } + + /** + * Closes the most recently opened form. + * @access public + */ + protected function acceptFormEnd() { + if (count($this->open_forms)) { + $this->complete_forms[] = array_pop($this->open_forms); + } + } + + /** + * Opens a frameset. A frameset may contain nested + * frameset tags. + * @param SimpleFramesetTag $tag Tag to accept. + * @access public + */ + protected function acceptFramesetStart($tag) { + if (! $this->isLoadingFrames()) { + $this->frameset = $tag; + } + $this->frameset_nesting_level++; + } + + /** + * Closes the most recently opened frameset. + * @access public + */ + protected function acceptFramesetEnd() { + if ($this->isLoadingFrames()) { + $this->frameset_nesting_level--; + } + } + + /** + * Takes a single frame tag and stashes it in + * the current frame set. + * @param SimpleFrameTag $tag Tag to accept. + * @access public + */ + protected function acceptFrame($tag) { + if ($this->isLoadingFrames()) { + if ($tag->getAttribute('src')) { + $this->loading_frames[] = $tag; + } + } + } + + /** + * Test to see if in the middle of reading + * a frameset. + * @return boolean True if inframeset. + * @access private + */ + protected function isLoadingFrames() { + return $this->frameset and $this->frameset_nesting_level > 0; + } + + /** + * Marker for end of complete page. Any work in + * progress can now be closed. + * @access public + */ + protected function acceptPageEnd() { + while (count($this->open_forms)) { + $this->complete_forms[] = array_pop($this->open_forms); + } + foreach ($this->left_over_labels as $label) { + for ($i = 0, $count = count($this->complete_forms); $i < $count; $i++) { + $this->complete_forms[$i]->attachLabelBySelector( + new SimpleById($label->getFor()), + $label->getText()); + } + } + $this->page->setForms($this->complete_forms); + $this->page->setFrames($this->loading_frames); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/reflection_php4.php b/application/libraries/simpletest/reflection_php4.php new file mode 100644 index 00000000000..39801ea1bdb --- /dev/null +++ b/application/libraries/simpletest/reflection_php4.php @@ -0,0 +1,136 @@ +_interface = $interface; + } + + /** + * Checks that a class has been declared. + * @return boolean True if defined. + * @access public + */ + function classExists() { + return class_exists($this->_interface); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classExistsSansAutoload() { + return class_exists($this->_interface); + } + + /** + * Checks that a class or interface has been + * declared. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExists() { + return class_exists($this->_interface); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExistsSansAutoload() { + return class_exists($this->_interface); + } + + /** + * Gets the list of methods on a class or + * interface. + * @returns array List of method names. + * @access public + */ + function getMethods() { + return get_class_methods($this->_interface); + } + + /** + * Gets the list of interfaces from a class. If the + * class name is actually an interface then just that + * interface is returned. + * @returns array List of interfaces. + * @access public + */ + function getInterfaces() { + return array(); + } + + /** + * Finds the parent class name. + * @returns string Parent class name. + * @access public + */ + function getParent() { + return strtolower(get_parent_class($this->_interface)); + } + + /** + * Determines if the class is abstract, which for PHP 4 + * will never be the case. + * @returns boolean True if abstract. + * @access public + */ + function isAbstract() { + return false; + } + + /** + * Determines if the the entity is an interface, which for PHP 4 + * will never be the case. + * @returns boolean True if interface. + * @access public + */ + function isInterface() { + return false; + } + + /** + * Scans for final methods, but as it's PHP 4 there + * aren't any. + * @returns boolean True if the class has a final method. + * @access public + */ + function hasFinal() { + return false; + } + + /** + * Gets the source code matching the declaration + * of a method. + * @param string $method Method name. + * @access public + */ + function getSignature($method) { + return "function &$method()"; + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/reflection_php5.php b/application/libraries/simpletest/reflection_php5.php new file mode 100644 index 00000000000..43d8a7b287f --- /dev/null +++ b/application/libraries/simpletest/reflection_php5.php @@ -0,0 +1,386 @@ +interface = $interface; + } + + /** + * Checks that a class has been declared. Versions + * before PHP5.0.2 need a check that it's not really + * an interface. + * @return boolean True if defined. + * @access public + */ + function classExists() { + if (! class_exists($this->interface)) { + return false; + } + $reflection = new ReflectionClass($this->interface); + return ! $reflection->isInterface(); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classExistsSansAutoload() { + return class_exists($this->interface, false); + } + + /** + * Checks that a class or interface has been + * declared. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExists() { + return $this->classOrInterfaceExistsWithAutoload($this->interface, true); + } + + /** + * Needed to kill the autoload feature in PHP5 + * for classes created dynamically. + * @return boolean True if defined. + * @access public + */ + function classOrInterfaceExistsSansAutoload() { + return $this->classOrInterfaceExistsWithAutoload($this->interface, false); + } + + /** + * Needed to select the autoload feature in PHP5 + * for classes created dynamically. + * @param string $interface Class or interface name. + * @param boolean $autoload True totriggerautoload. + * @return boolean True if interface defined. + * @access private + */ + protected function classOrInterfaceExistsWithAutoload($interface, $autoload) { + if (function_exists('interface_exists')) { + if (interface_exists($this->interface, $autoload)) { + return true; + } + } + return class_exists($this->interface, $autoload); + } + + /** + * Gets the list of methods on a class or + * interface. + * @returns array List of method names. + * @access public + */ + function getMethods() { + return array_unique(get_class_methods($this->interface)); + } + + /** + * Gets the list of interfaces from a class. If the + * class name is actually an interface then just that + * interface is returned. + * @returns array List of interfaces. + * @access public + */ + function getInterfaces() { + $reflection = new ReflectionClass($this->interface); + if ($reflection->isInterface()) { + return array($this->interface); + } + return $this->onlyParents($reflection->getInterfaces()); + } + + /** + * Gets the list of methods for the implemented + * interfaces only. + * @returns array List of enforced method signatures. + * @access public + */ + function getInterfaceMethods() { + $methods = array(); + foreach ($this->getInterfaces() as $interface) { + $methods = array_merge($methods, get_class_methods($interface)); + } + return array_unique($methods); + } + + /** + * Checks to see if the method signature has to be tightly + * specified. + * @param string $method Method name. + * @returns boolean True if enforced. + * @access private + */ + protected function isInterfaceMethod($method) { + return in_array($method, $this->getInterfaceMethods()); + } + + /** + * Finds the parent class name. + * @returns string Parent class name. + * @access public + */ + function getParent() { + $reflection = new ReflectionClass($this->interface); + $parent = $reflection->getParentClass(); + if ($parent) { + return $parent->getName(); + } + return false; + } + + /** + * Trivially determines if the class is abstract. + * @returns boolean True if abstract. + * @access public + */ + function isAbstract() { + $reflection = new ReflectionClass($this->interface); + return $reflection->isAbstract(); + } + + /** + * Trivially determines if the class is an interface. + * @returns boolean True if interface. + * @access public + */ + function isInterface() { + $reflection = new ReflectionClass($this->interface); + return $reflection->isInterface(); + } + + /** + * Scans for final methods, as they screw up inherited + * mocks by not allowing you to override them. + * @returns boolean True if the class has a final method. + * @access public + */ + function hasFinal() { + $reflection = new ReflectionClass($this->interface); + foreach ($reflection->getMethods() as $method) { + if ($method->isFinal()) { + return true; + } + } + return false; + } + + /** + * Whittles a list of interfaces down to only the + * necessary top level parents. + * @param array $interfaces Reflection API interfaces + * to reduce. + * @returns array List of parent interface names. + * @access private + */ + protected function onlyParents($interfaces) { + $parents = array(); + $blacklist = array(); + foreach ($interfaces as $interface) { + foreach($interfaces as $possible_parent) { + if ($interface->getName() == $possible_parent->getName()) { + continue; + } + if ($interface->isSubClassOf($possible_parent)) { + $blacklist[$possible_parent->getName()] = true; + } + } + if (!isset($blacklist[$interface->getName()])) { + $parents[] = $interface->getName(); + } + } + return $parents; + } + + /** + * Checks whether a method is abstract or not. + * @param string $name Method name. + * @return bool true if method is abstract, else false + * @access private + */ + protected function isAbstractMethod($name) { + $interface = new ReflectionClass($this->interface); + if (! $interface->hasMethod($name)) { + return false; + } + return $interface->getMethod($name)->isAbstract(); + } + + /** + * Checks whether a method is the constructor. + * @param string $name Method name. + * @return bool true if method is the constructor + * @access private + */ + protected function isConstructor($name) { + return ($name == '__construct') || ($name == $this->interface); + } + + /** + * Checks whether a method is abstract in all parents or not. + * @param string $name Method name. + * @return bool true if method is abstract in parent, else false + * @access private + */ + protected function isAbstractMethodInParents($name) { + $interface = new ReflectionClass($this->interface); + $parent = $interface->getParentClass(); + while($parent) { + if (! $parent->hasMethod($name)) { + return false; + } + if ($parent->getMethod($name)->isAbstract()) { + return true; + } + $parent = $parent->getParentClass(); + } + return false; + } + + /** + * Checks whether a method is static or not. + * @param string $name Method name + * @return bool true if method is static, else false + * @access private + */ + protected function isStaticMethod($name) { + $interface = new ReflectionClass($this->interface); + if (! $interface->hasMethod($name)) { + return false; + } + return $interface->getMethod($name)->isStatic(); + } + + /** + * Writes the source code matching the declaration + * of a method. + * @param string $name Method name. + * @return string Method signature up to last + * bracket. + * @access public + */ + function getSignature($name) { + if ($name == '__set') { + return 'function __set($key, $value)'; + } + if ($name == '__call') { + return 'function __call($method, $arguments)'; + } + if (version_compare(phpversion(), '5.1.0', '>=')) { + if (in_array($name, array('__get', '__isset', $name == '__unset'))) { + return "function {$name}(\$key)"; + } + } + if ($name == '__toString') { + return "function $name()"; + } + + // This wonky try-catch is a work around for a faulty method_exists() + // in early versions of PHP 5 which would return false for static + // methods. The Reflection classes work fine, but hasMethod() + // doesn't exist prior to PHP 5.1.0, so we need to use a more crude + // detection method. + try { + $interface = new ReflectionClass($this->interface); + $interface->getMethod($name); + } catch (ReflectionException $e) { + return "function $name()"; + } + return $this->getFullSignature($name); + } + + /** + * For a signature specified in an interface, full + * details must be replicated to be a valid implementation. + * @param string $name Method name. + * @return string Method signature up to last + * bracket. + * @access private + */ + protected function getFullSignature($name) { + $interface = new ReflectionClass($this->interface); + $method = $interface->getMethod($name); + $reference = $method->returnsReference() ? '&' : ''; + $static = $method->isStatic() ? 'static ' : ''; + return "{$static}function $reference$name(" . + implode(', ', $this->getParameterSignatures($method)) . + ")"; + } + + /** + * Gets the source code for each parameter. + * @param ReflectionMethod $method Method object from + * reflection API + * @return array List of strings, each + * a snippet of code. + * @access private + */ + protected function getParameterSignatures($method) { + $signatures = array(); + foreach ($method->getParameters() as $parameter) { + $signature = ''; + $type = $parameter->getClass(); + if (is_null($type) && version_compare(phpversion(), '5.1.0', '>=') && $parameter->isArray()) { + $signature .= 'array '; + } elseif (!is_null($type)) { + $signature .= $type->getName() . ' '; + } + if ($parameter->isPassedByReference()) { + $signature .= '&'; + } + $signature .= '$' . $this->suppressSpurious($parameter->getName()); + if ($this->isOptional($parameter)) { + $signature .= ' = null'; + } + $signatures[] = $signature; + } + return $signatures; + } + + /** + * The SPL library has problems with the + * Reflection library. In particular, you can + * get extra characters in parameter names :(. + * @param string $name Parameter name. + * @return string Cleaner name. + * @access private + */ + protected function suppressSpurious($name) { + return str_replace(array('[', ']', ' '), '', $name); + } + + /** + * Test of a reflection parameter being optional + * that works with early versions of PHP5. + * @param reflectionParameter $parameter Is this optional. + * @return boolean True if optional. + * @access private + */ + protected function isOptional($parameter) { + if (method_exists($parameter, 'isOptional')) { + return $parameter->isOptional(); + } + return false; + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/remote.php b/application/libraries/simpletest/remote.php new file mode 100644 index 00000000000..4bb37b7c51b --- /dev/null +++ b/application/libraries/simpletest/remote.php @@ -0,0 +1,115 @@ +url = $url; + $this->dry_url = $dry_url ? $dry_url : $url; + $this->size = false; + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->url; + } + + /** + * Runs the top level test for this class. Currently + * reads the data as a single chunk. I'll fix this + * once I have added iteration to the browser. + * @param SimpleReporter $reporter Target of test results. + * @returns boolean True if no failures. + * @access public + */ + function run($reporter) { + $browser = $this->createBrowser(); + $xml = $browser->get($this->url); + if (! $xml) { + trigger_error('Cannot read remote test URL [' . $this->url . ']'); + return false; + } + $parser = $this->createParser($reporter); + if (! $parser->parse($xml)) { + trigger_error('Cannot parse incoming XML from [' . $this->url . ']'); + return false; + } + return true; + } + + /** + * Creates a new web browser object for fetching + * the XML report. + * @return SimpleBrowser New browser. + * @access protected + */ + protected function createBrowser() { + return new SimpleBrowser(); + } + + /** + * Creates the XML parser. + * @param SimpleReporter $reporter Target of test results. + * @return SimpleTestXmlListener XML reader. + * @access protected + */ + protected function createParser($reporter) { + return new SimpleTestXmlParser($reporter); + } + + /** + * Accessor for the number of subtests. + * @return integer Number of test cases. + * @access public + */ + function getSize() { + if ($this->size === false) { + $browser = $this->createBrowser(); + $xml = $browser->get($this->dry_url); + if (! $xml) { + trigger_error('Cannot read remote test URL [' . $this->dry_url . ']'); + return false; + } + $reporter = new SimpleReporter(); + $parser = $this->createParser($reporter); + if (! $parser->parse($xml)) { + trigger_error('Cannot parse incoming XML from [' . $this->dry_url . ']'); + return false; + } + $this->size = $reporter->getTestCaseCount(); + } + return $this->size; + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/reporter.php b/application/libraries/simpletest/reporter.php new file mode 100644 index 00000000000..bf8d2ac1155 --- /dev/null +++ b/application/libraries/simpletest/reporter.php @@ -0,0 +1,445 @@ +character_set = $character_set; + } + + /** + * Paints the top of the web page setting the + * title to the name of the starting test. + * @param string $test_name Name class of test. + * @access public + */ + function paintHeader($test_name) { + $this->sendNoCacheHeaders(); + print ""; + print "\n\n$test_name\n"; + print "\n"; + print "\n"; + print "\n\n"; + print "

    $test_name

    \n"; + flush(); + } + + /** + * Send the headers necessary to ensure the page is + * reloaded on every request. Otherwise you could be + * scratching your head over out of date test data. + * @access public + */ + static function sendNoCacheHeaders() { + if (! headers_sent()) { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Cache-Control: post-check=0, pre-check=0", false); + header("Pragma: no-cache"); + } + } + + /** + * Paints the CSS. Add additional styles here. + * @return string CSS code as text. + * @access protected + */ + protected function getCss() { + return ".fail { background-color: inherit; color: red; }" . + ".pass { background-color: inherit; color: green; }" . + " pre { background-color: lightgray; color: inherit; }"; + } + + /** + * Paints the end of the test with a summary of + * the passes and failures. + * @param string $test_name Name class of test. + * @access public + */ + function paintFooter($test_name) { + $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green"); + print "
    "; + print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount(); + print " test cases complete:\n"; + print "" . $this->getPassCount() . " passes, "; + print "" . $this->getFailCount() . " fails and "; + print "" . $this->getExceptionCount() . " exceptions."; + print "
    \n"; + print "\n\n"; + } + + /** + * Paints the test failure with a breadcrumbs + * trail of the nesting test suites below the + * top level test. + * @param string $message Failure message displayed in + * the context of the other tests. + */ + function paintFail($message) { + parent::paintFail($message); + print "Fail: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints a PHP error. + * @param string $message Message is ignored. + * @access public + */ + function paintError($message) { + parent::paintError($message); + print "Exception: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints a PHP exception. + * @param Exception $exception Exception to display. + * @access public + */ + function paintException($exception) { + parent::paintException($exception); + print "Exception: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + $message = 'Unexpected exception of type [' . get_class($exception) . + '] with message ['. $exception->getMessage() . + '] in ['. $exception->getFile() . + ' line ' . $exception->getLine() . ']'; + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + parent::paintSkip($message); + print "Skipped: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . $this->htmlEntities($message) . "
    \n"; + } + + /** + * Paints formatted text such as dumped privateiables. + * @param string $message Text to show. + * @access public + */ + function paintFormattedMessage($message) { + print '
    ' . $this->htmlEntities($message) . '
    '; + } + + /** + * Character set adjusted entity conversion. + * @param string $message Plain text or Unicode message. + * @return string Browser readable message. + * @access protected + */ + protected function htmlEntities($message) { + return htmlentities($message, ENT_COMPAT, $this->character_set); + } +} + +/** + * Sample minimal test displayer. Generates only + * failure messages and a pass count. For command + * line use. I've tried to make it look like JUnit, + * but I wanted to output the errors as they arrived + * which meant dropping the dots. + * @package SimpleTest + * @subpackage UnitTester + */ +class TextReporter extends SimpleReporter { + + /** + * Does nothing yet. The first output will + * be sent on the first test start. + */ + function __construct() { + parent::__construct(); + } + + /** + * Paints the title only. + * @param string $test_name Name class of test. + * @access public + */ + function paintHeader($test_name) { + if (! SimpleReporter::inCli()) { + header('Content-type: text/plain'); + } + print "$test_name\n"; + flush(); + } + + /** + * Paints the end of the test with a summary of + * the passes and failures. + * @param string $test_name Name class of test. + * @access public + */ + function paintFooter($test_name) { + if ($this->getFailCount() + $this->getExceptionCount() == 0) { + print "OK\n"; + } else { + print "FAILURES!!!\n"; + } + print "Test cases run: " . $this->getTestCaseProgress() . + "/" . $this->getTestCaseCount() . + ", Passes: " . $this->getPassCount() . + ", Failures: " . $this->getFailCount() . + ", Exceptions: " . $this->getExceptionCount() . "\n"; + } + + /** + * Paints the test failure as a stack trace. + * @param string $message Failure message displayed in + * the context of the other tests. + * @access public + */ + function paintFail($message) { + parent::paintFail($message); + print $this->getFailCount() . ") $message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Paints a PHP error or exception. + * @param string $message Message to be shown. + * @access public + * @abstract + */ + function paintError($message) { + parent::paintError($message); + print "Exception " . $this->getExceptionCount() . "!\n$message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Paints a PHP error or exception. + * @param Exception $exception Exception to describe. + * @access public + * @abstract + */ + function paintException($exception) { + parent::paintException($exception); + $message = 'Unexpected exception of type [' . get_class($exception) . + '] with message ['. $exception->getMessage() . + '] in ['. $exception->getFile() . + ' line ' . $exception->getLine() . ']'; + print "Exception " . $this->getExceptionCount() . "!\n$message\n"; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print "\tin " . implode("\n\tin ", array_reverse($breadcrumb)); + print "\n"; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + parent::paintSkip($message); + print "Skip: $message\n"; + } + + /** + * Paints formatted text such as dumped privateiables. + * @param string $message Text to show. + * @access public + */ + function paintFormattedMessage($message) { + print "$message\n"; + flush(); + } +} + +/** + * Runs just a single test group, a single case or + * even a single test within that case. + * @package SimpleTest + * @subpackage UnitTester + */ +class SelectiveReporter extends SimpleReporterDecorator { + private $just_this_case = false; + private $just_this_test = false; + private $on; + + /** + * Selects the test case or group to be run, + * and optionally a specific test. + * @param SimpleScorer $reporter Reporter to receive events. + * @param string $just_this_case Only this case or group will run. + * @param string $just_this_test Only this test method will run. + */ + function __construct($reporter, $just_this_case = false, $just_this_test = false) { + if (isset($just_this_case) && $just_this_case) { + $this->just_this_case = strtolower($just_this_case); + $this->off(); + } else { + $this->on(); + } + if (isset($just_this_test) && $just_this_test) { + $this->just_this_test = strtolower($just_this_test); + } + parent::__construct($reporter); + } + + /** + * Compares criteria to actual the case/group name. + * @param string $test_case The incoming test. + * @return boolean True if matched. + * @access protected + */ + protected function matchesTestCase($test_case) { + return $this->just_this_case == strtolower($test_case); + } + + /** + * Compares criteria to actual the test name. If no + * name was specified at the beginning, then all tests + * can run. + * @param string $method The incoming test method. + * @return boolean True if matched. + * @access protected + */ + protected function shouldRunTest($test_case, $method) { + if ($this->isOn() || $this->matchesTestCase($test_case)) { + if ($this->just_this_test) { + return $this->just_this_test == strtolower($method); + } else { + return true; + } + } + return false; + } + + /** + * Switch on testing for the group or subgroup. + * @access private + */ + protected function on() { + $this->on = true; + } + + /** + * Switch off testing for the group or subgroup. + * @access private + */ + protected function off() { + $this->on = false; + } + + /** + * Is this group actually being tested? + * @return boolean True if the current test group is active. + * @access private + */ + protected function isOn() { + return $this->on; + } + + /** + * Veto everything that doesn't match the method wanted. + * @param string $test_case Name of test case. + * @param string $method Name of test method. + * @return boolean True if test should be run. + * @access public + */ + function shouldInvoke($test_case, $method) { + if ($this->shouldRunTest($test_case, $method)) { + return $this->reporter->shouldInvoke($test_case, $method); + } + return false; + } + + /** + * Paints the start of a group test. + * @param string $test_case Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_case, $size) { + if ($this->just_this_case && $this->matchesTestCase($test_case)) { + $this->on(); + } + $this->reporter->paintGroupStart($test_case, $size); + } + + /** + * Paints the end of a group test. + * @param string $test_case Name of test or other label. + * @access public + */ + function paintGroupEnd($test_case) { + $this->reporter->paintGroupEnd($test_case); + if ($this->just_this_case && $this->matchesTestCase($test_case)) { + $this->off(); + } + } +} + +/** + * Suppresses skip messages. + * @package SimpleTest + * @subpackage UnitTester + */ +class NoSkipsReporter extends SimpleReporterDecorator { + + /** + * Does nothing. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/scorer.php b/application/libraries/simpletest/scorer.php new file mode 100644 index 00000000000..27776f4b631 --- /dev/null +++ b/application/libraries/simpletest/scorer.php @@ -0,0 +1,875 @@ +passes = 0; + $this->fails = 0; + $this->exceptions = 0; + $this->is_dry_run = false; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + $this->is_dry_run = $is_dry; + } + + /** + * The reporter has a veto on what should be run. + * @param string $test_case_name name of test case. + * @param string $method Name of test method. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + return ! $this->is_dry_run; + } + + /** + * Can wrap the invoker in preperation for running + * a test. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + return $invoker; + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * Used for command line tools. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + if ($this->exceptions + $this->fails > 0) { + return false; + } + return true; + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + } + + /** + * Increments the pass count. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + $this->passes++; + } + + /** + * Increments the fail count. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + $this->fails++; + } + + /** + * Deals with PHP 4 throwing an error. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + $this->exceptions++; + } + + /** + * Deals with PHP 5 throwing an exception. + * @param Exception $exception The actual exception thrown. + * @access public + */ + function paintException($exception) { + $this->exceptions++; + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + } + + /** + * Accessor for the number of passes so far. + * @return integer Number of passes. + * @access public + */ + function getPassCount() { + return $this->passes; + } + + /** + * Accessor for the number of fails so far. + * @return integer Number of fails. + * @access public + */ + function getFailCount() { + return $this->fails; + } + + /** + * Accessor for the number of untrapped errors + * so far. + * @return integer Number of exceptions. + * @access public + */ + function getExceptionCount() { + return $this->exceptions; + } + + /** + * Paints a simple supplementary message. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + } + + /** + * Paints a formatted ASCII message such as a + * privateiable dump. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + } + + /** + * By default just ignores user generated events. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @access public + */ + function paintSignal($type, $payload) { + } +} + +/** + * Recipient of generated test messages that can display + * page footers and headers. Also keeps track of the + * test nesting. This is the main base class on which + * to build the finished test (page based) displays. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleReporter extends SimpleScorer { + private $test_stack; + private $size; + private $progress; + + /** + * Starts the display with no results in. + * @access public + */ + function __construct() { + parent::__construct(); + $this->test_stack = array(); + $this->size = null; + $this->progress = 0; + } + + /** + * Gets the formatter for small generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return new SimpleDumper(); + } + + /** + * Paints the start of a group test. Will also paint + * the page header and footer if this is the + * first test. Will stash the size if the first + * start. + * @param string $test_name Name of test that is starting. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + if (! isset($this->size)) { + $this->size = $size; + } + if (count($this->test_stack) == 0) { + $this->paintHeader($test_name); + } + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a group test. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @param integer $progress Number of test cases ending. + * @access public + */ + function paintGroupEnd($test_name) { + array_pop($this->test_stack); + if (count($this->test_stack) == 0) { + $this->paintFooter($test_name); + } + } + + /** + * Paints the start of a test case. Will also paint + * the page header and footer if this is the + * first test. Will stash the size if the first + * start. + * @param string $test_name Name of test that is starting. + * @access public + */ + function paintCaseStart($test_name) { + if (! isset($this->size)) { + $this->size = 1; + } + if (count($this->test_stack) == 0) { + $this->paintHeader($test_name); + } + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a test case. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @access public + */ + function paintCaseEnd($test_name) { + $this->progress++; + array_pop($this->test_stack); + if (count($this->test_stack) == 0) { + $this->paintFooter($test_name); + } + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test that is starting. + * @access public + */ + function paintMethodStart($test_name) { + $this->test_stack[] = $test_name; + } + + /** + * Paints the end of a test method. Will paint the page + * footer if the stack of tests has unwound. + * @param string $test_name Name of test that is ending. + * @access public + */ + function paintMethodEnd($test_name) { + array_pop($this->test_stack); + } + + /** + * Paints the test document header. + * @param string $test_name First test top level + * to start. + * @access public + * @abstract + */ + function paintHeader($test_name) { + } + + /** + * Paints the test document footer. + * @param string $test_name The top level test. + * @access public + * @abstract + */ + function paintFooter($test_name) { + } + + /** + * Accessor for internal test stack. For + * subclasses that need to see the whole test + * history for display purposes. + * @return array List of methods in nesting order. + * @access public + */ + function getTestList() { + return $this->test_stack; + } + + /** + * Accessor for total test size in number + * of test cases. Null until the first + * test is started. + * @return integer Total number of cases at start. + * @access public + */ + function getTestCaseCount() { + return $this->size; + } + + /** + * Accessor for the number of test cases + * completed so far. + * @return integer Number of ended cases. + * @access public + */ + function getTestCaseProgress() { + return $this->progress; + } + + /** + * Static check for running in the comand line. + * @return boolean True if CLI. + * @access public + */ + static function inCli() { + return php_sapi_name() == 'cli'; + } +} + +/** + * For modifying the behaviour of the visual reporters. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleReporterDecorator { + protected $reporter; + + /** + * Mediates between the reporter and the test case. + * @param SimpleScorer $reporter Reporter to receive events. + */ + function __construct($reporter) { + $this->reporter = $reporter; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + $this->reporter->makeDry($is_dry); + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * Used for command line tools. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + return $this->reporter->getStatus(); + } + + /** + * The nesting of the test cases so far. Not + * all reporters have this facility. + * @return array Test list if accessible. + * @access public + */ + function getTestList() { + if (method_exists($this->reporter, 'getTestList')) { + return $this->reporter->getTestList(); + } else { + return array(); + } + } + + /** + * The reporter has a veto on what should be run. + * @param string $test_case_name Name of test case. + * @param string $method Name of test method. + * @return boolean True if test should be run. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + return $this->reporter->shouldInvoke($test_case_name, $method); + } + + /** + * Can wrap the invoker in preparation for running + * a test. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + return $this->reporter->createInvoker($invoker); + } + + /** + * Gets the formatter for privateiables and other small + * generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return $this->reporter->getDumper(); + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + $this->reporter->paintGroupStart($test_name, $size); + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + $this->reporter->paintGroupEnd($test_name); + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + $this->reporter->paintCaseStart($test_name); + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + $this->reporter->paintCaseEnd($test_name); + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + $this->reporter->paintMethodStart($test_name); + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + $this->reporter->paintMethodEnd($test_name); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + $this->reporter->paintPass($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + $this->reporter->paintFail($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + $this->reporter->paintError($message); + } + + /** + * Chains to the wrapped reporter. + * @param Exception $exception Exception to show. + * @access public + */ + function paintException($exception) { + $this->reporter->paintException($exception); + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + $this->reporter->paintSkip($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + $this->reporter->paintMessage($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + $this->reporter->paintFormattedMessage($message); + } + + /** + * Chains to the wrapped reporter. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @return boolean Should return false if this + * type of signal should fail the + * test suite. + * @access public + */ + function paintSignal($type, $payload) { + $this->reporter->paintSignal($type, $payload); + } +} + +/** + * For sending messages to multiple reporters at + * the same time. + * @package SimpleTest + * @subpackage UnitTester + */ +class MultipleReporter { + private $reporters = array(); + + /** + * Adds a reporter to the subscriber list. + * @param SimpleScorer $reporter Reporter to receive events. + * @access public + */ + function attachReporter($reporter) { + $this->reporters[] = $reporter; + } + + /** + * Signals that the next evaluation will be a dry + * run. That is, the structure events will be + * recorded, but no tests will be run. + * @param boolean $is_dry Dry run if true. + * @access public + */ + function makeDry($is_dry = true) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->makeDry($is_dry); + } + } + + /** + * Accessor for current status. Will be false + * if there have been any failures or exceptions. + * If any reporter reports a failure, the whole + * suite fails. + * @return boolean True if no failures. + * @access public + */ + function getStatus() { + for ($i = 0; $i < count($this->reporters); $i++) { + if (! $this->reporters[$i]->getStatus()) { + return false; + } + } + return true; + } + + /** + * The reporter has a veto on what should be run. + * It requires all reporters to want to run the method. + * @param string $test_case_name name of test case. + * @param string $method Name of test method. + * @access public + */ + function shouldInvoke($test_case_name, $method) { + for ($i = 0; $i < count($this->reporters); $i++) { + if (! $this->reporters[$i]->shouldInvoke($test_case_name, $method)) { + return false; + } + } + return true; + } + + /** + * Every reporter gets a chance to wrap the invoker. + * @param SimpleInvoker $invoker Individual test runner. + * @return SimpleInvoker Wrapped test runner. + * @access public + */ + function createInvoker($invoker) { + for ($i = 0; $i < count($this->reporters); $i++) { + $invoker = $this->reporters[$i]->createInvoker($invoker); + } + return $invoker; + } + + /** + * Gets the formatter for privateiables and other small + * generic data items. + * @return SimpleDumper Formatter. + * @access public + */ + function getDumper() { + return new SimpleDumper(); + } + + /** + * Paints the start of a group test. + * @param string $test_name Name of test or other label. + * @param integer $size Number of test cases starting. + * @access public + */ + function paintGroupStart($test_name, $size) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintGroupStart($test_name, $size); + } + } + + /** + * Paints the end of a group test. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintGroupEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintGroupEnd($test_name); + } + } + + /** + * Paints the start of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseStart($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintCaseStart($test_name); + } + } + + /** + * Paints the end of a test case. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintCaseEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintCaseEnd($test_name); + } + } + + /** + * Paints the start of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodStart($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMethodStart($test_name); + } + } + + /** + * Paints the end of a test method. + * @param string $test_name Name of test or other label. + * @access public + */ + function paintMethodEnd($test_name) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMethodEnd($test_name); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintPass($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintPass($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Message is ignored. + * @access public + */ + function paintFail($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintFail($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text of error formatted by + * the test case. + * @access public + */ + function paintError($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintError($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param Exception $exception Exception to display. + * @access public + */ + function paintException($exception) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintException($exception); + } + } + + /** + * Prints the message for skipping tests. + * @param string $message Text of skip condition. + * @access public + */ + function paintSkip($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintSkip($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintMessage($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintMessage($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $message Text to display. + * @access public + */ + function paintFormattedMessage($message) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintFormattedMessage($message); + } + } + + /** + * Chains to the wrapped reporter. + * @param string $type Event type as text. + * @param mixed $payload Message or object. + * @return boolean Should return false if this + * type of signal should fail the + * test suite. + * @access public + */ + function paintSignal($type, $payload) { + for ($i = 0; $i < count($this->reporters); $i++) { + $this->reporters[$i]->paintSignal($type, $payload); + } + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/selector.php b/application/libraries/simpletest/selector.php new file mode 100644 index 00000000000..ba2fed312a8 --- /dev/null +++ b/application/libraries/simpletest/selector.php @@ -0,0 +1,141 @@ +name = $name; + } + + /** + * Accessor for name. + * @returns string $name Name to match. + */ + function getName() { + return $this->name; + } + + /** + * Compares with name attribute of widget. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + return ($widget->getName() == $this->name); + } +} + +/** + * Used to extract form elements for testing against. + * Searches by visible label or alt text. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleByLabel { + private $label; + + /** + * Stashes the name for later comparison. + * @param string $label Visible text to match. + */ + function __construct($label) { + $this->label = $label; + } + + /** + * Comparison. Compares visible text of widget or + * related label. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + if (! method_exists($widget, 'isLabel')) { + return false; + } + return $widget->isLabel($this->label); + } +} + +/** + * Used to extract form elements for testing against. + * Searches dy id attribute. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleById { + private $id; + + /** + * Stashes the name for later comparison. + * @param string $id ID atribute to match. + */ + function __construct($id) { + $this->id = $id; + } + + /** + * Comparison. Compares id attribute of widget. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + return $widget->isId($this->id); + } +} + +/** + * Used to extract form elements for testing against. + * Searches by visible label, name or alt text. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleByLabelOrName { + private $label; + + /** + * Stashes the name/label for later comparison. + * @param string $label Visible text to match. + */ + function __construct($label) { + $this->label = $label; + } + + /** + * Comparison. Compares visible text of widget or + * related label or name. + * @param SimpleWidget $widget Control to compare. + * @access public + */ + function isMatch($widget) { + if (method_exists($widget, 'isLabel')) { + if ($widget->isLabel($this->label)) { + return true; + } + } + return ($widget->getName() == $this->label); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/shell_tester.php b/application/libraries/simpletest/shell_tester.php new file mode 100644 index 00000000000..9a3bd389eeb --- /dev/null +++ b/application/libraries/simpletest/shell_tester.php @@ -0,0 +1,330 @@ +output = false; + } + + /** + * Actually runs the command. Does not trap the + * error stream output as this need PHP 4.3+. + * @param string $command The actual command line + * to run. + * @return integer Exit code. + * @access public + */ + function execute($command) { + $this->output = false; + exec($command, $this->output, $ret); + return $ret; + } + + /** + * Accessor for the last output. + * @return string Output as text. + * @access public + */ + function getOutput() { + return implode("\n", $this->output); + } + + /** + * Accessor for the last output. + * @return array Output as array of lines. + * @access public + */ + function getOutputAsList() { + return $this->output; + } +} + +/** + * Test case for testing of command line scripts and + * utilities. Usually scripts that are external to the + * PHP code, but support it in some way. + * @package SimpleTest + * @subpackage UnitTester + */ +class ShellTestCase extends SimpleTestCase { + private $current_shell; + private $last_status; + private $last_command; + + /** + * Creates an empty test case. Should be subclassed + * with test methods for a functional test case. + * @param string $label Name of test case. Will use + * the class name if none specified. + * @access public + */ + function __construct($label = false) { + parent::__construct($label); + $this->current_shell = $this->createShell(); + $this->last_status = false; + $this->last_command = ''; + } + + /** + * Executes a command and buffers the results. + * @param string $command Command to run. + * @return boolean True if zero exit code. + * @access public + */ + function execute($command) { + $shell = $this->getShell(); + $this->last_status = $shell->execute($command); + $this->last_command = $command; + return ($this->last_status === 0); + } + + /** + * Dumps the output of the last command. + * @access public + */ + function dumpOutput() { + $this->dump($this->getOutput()); + } + + /** + * Accessor for the last output. + * @return string Output as text. + * @access public + */ + function getOutput() { + $shell = $this->getShell(); + return $shell->getOutput(); + } + + /** + * Accessor for the last output. + * @return array Output as array of lines. + * @access public + */ + function getOutputAsList() { + $shell = $this->getShell(); + return $shell->getOutputAsList(); + } + + /** + * Called from within the test methods to register + * passes and failures. + * @param boolean $result Pass on true. + * @param string $message Message to display describing + * the test state. + * @return boolean True on pass + * @access public + */ + function assertTrue($result, $message = false) { + return $this->assert(new TrueExpectation(), $result, $message); + } + + /** + * Will be true on false and vice versa. False + * is the PHP definition of false, so that null, + * empty strings, zero and an empty array all count + * as false. + * @param boolean $result Pass on false. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertFalse($result, $message = '%s') { + return $this->assert(new FalseExpectation(), $result, $message); + } + + /** + * Will trigger a pass if the two parameters have + * the same value only. Otherwise a fail. This + * is for testing hand extracted text, etc. + * @param mixed $first Value to compare. + * @param mixed $second Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertEqual($first, $second, $message = "%s") { + return $this->assert( + new EqualExpectation($first), + $second, + $message); + } + + /** + * Will trigger a pass if the two parameters have + * a different value. Otherwise a fail. This + * is for testing hand extracted text, etc. + * @param mixed $first Value to compare. + * @param mixed $second Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assertNotEqual($first, $second, $message = "%s") { + return $this->assert( + new NotEqualExpectation($first), + $second, + $message); + } + + /** + * Tests the last status code from the shell. + * @param integer $status Expected status of last + * command. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertExitCode($status, $message = "%s") { + $message = sprintf($message, "Expected status code of [$status] from [" . + $this->last_command . "], but got [" . + $this->last_status . "]"); + return $this->assertTrue($status === $this->last_status, $message); + } + + /** + * Attempt to exactly match the combined STDERR and + * STDOUT output. + * @param string $expected Expected output. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertOutput($expected, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new EqualExpectation($expected), + $shell->getOutput(), + $message); + } + + /** + * Scans the output for a Perl regex. If found + * anywhere it passes, else it fails. + * @param string $pattern Regex to search for. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertOutputPattern($pattern, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new PatternExpectation($pattern), + $shell->getOutput(), + $message); + } + + /** + * If a Perl regex is found anywhere in the current + * output then a failure is generated, else a pass. + * @param string $pattern Regex to search for. + * @param $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertNoOutputPattern($pattern, $message = "%s") { + $shell = $this->getShell(); + return $this->assert( + new NoPatternExpectation($pattern), + $shell->getOutput(), + $message); + } + + /** + * File existence check. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFileExists($path, $message = "%s") { + $message = sprintf($message, "File [$path] should exist"); + return $this->assertTrue(file_exists($path), $message); + } + + /** + * File non-existence check. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFileNotExists($path, $message = "%s") { + $message = sprintf($message, "File [$path] should not exist"); + return $this->assertFalse(file_exists($path), $message); + } + + /** + * Scans a file for a Perl regex. If found + * anywhere it passes, else it fails. + * @param string $pattern Regex to search for. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertFilePattern($pattern, $path, $message = "%s") { + return $this->assert( + new PatternExpectation($pattern), + implode('', file($path)), + $message); + } + + /** + * If a Perl regex is found anywhere in the named + * file then a failure is generated, else a pass. + * @param string $pattern Regex to search for. + * @param string $path Full filename and path. + * @param string $message Message to display. + * @return boolean True if pass. + * @access public + */ + function assertNoFilePattern($pattern, $path, $message = "%s") { + return $this->assert( + new NoPatternExpectation($pattern), + implode('', file($path)), + $message); + } + + /** + * Accessor for current shell. Used for testing the + * the tester itself. + * @return Shell Current shell. + * @access protected + */ + protected function getShell() { + return $this->current_shell; + } + + /** + * Factory for the shell to run the command on. + * @return Shell New shell object. + * @access protected + */ + protected function createShell() { + return new SimpleShell(); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/simpletest.php b/application/libraries/simpletest/simpletest.php new file mode 100644 index 00000000000..425c869a825 --- /dev/null +++ b/application/libraries/simpletest/simpletest.php @@ -0,0 +1,391 @@ +getParent()) { + SimpleTest::ignore($parent); + } + } + } + } + + /** + * Puts the object to the global pool of 'preferred' objects + * which can be retrieved with SimpleTest :: preferred() method. + * Instances of the same class are overwritten. + * @param object $object Preferred object + * @see preferred() + */ + static function prefer($object) { + $registry = &SimpleTest::getRegistry(); + $registry['Preferred'][] = $object; + } + + /** + * Retrieves 'preferred' objects from global pool. Class filter + * can be applied in order to retrieve the object of the specific + * class + * @param array|string $classes Allowed classes or interfaces. + * @return array|object|null + * @see prefer() + */ + static function preferred($classes) { + if (! is_array($classes)) { + $classes = array($classes); + } + $registry = &SimpleTest::getRegistry(); + for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) { + foreach ($classes as $class) { + if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) { + return $registry['Preferred'][$i]; + } + } + } + return null; + } + + /** + * Test to see if a test case is in the ignore + * list. Quite obviously the ignore list should + * be a separate object and will be one day. + * This method is internal to SimpleTest. Don't + * use it. + * @param string $class Class name to test. + * @return boolean True if should not be run. + */ + static function isIgnored($class) { + $registry = &SimpleTest::getRegistry(); + return isset($registry['IgnoreList'][strtolower($class)]); + } + + /** + * Sets proxy to use on all requests for when + * testing from behind a firewall. Set host + * to false to disable. This will take effect + * if there are no other proxy settings. + * @param string $proxy Proxy host as URL. + * @param string $username Proxy username for authentication. + * @param string $password Proxy password for authentication. + */ + static function useProxy($proxy, $username = false, $password = false) { + $registry = &SimpleTest::getRegistry(); + $registry['DefaultProxy'] = $proxy; + $registry['DefaultProxyUsername'] = $username; + $registry['DefaultProxyPassword'] = $password; + } + + /** + * Accessor for default proxy host. + * @return string Proxy URL. + */ + static function getDefaultProxy() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxy']; + } + + /** + * Accessor for default proxy username. + * @return string Proxy username for authentication. + */ + static function getDefaultProxyUsername() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxyUsername']; + } + + /** + * Accessor for default proxy password. + * @return string Proxy password for authentication. + */ + static function getDefaultProxyPassword() { + $registry = &SimpleTest::getRegistry(); + return $registry['DefaultProxyPassword']; + } + + /** + * Accessor for default HTML parsers. + * @return array List of parsers to try in + * order until one responds true + * to can(). + */ + static function getParsers() { + $registry = &SimpleTest::getRegistry(); + return $registry['Parsers']; + } + + /** + * Set the list of HTML parsers to attempt to use by default. + * @param array $parsers List of parsers to try in + * order until one responds true + * to can(). + */ + static function setParsers($parsers) { + $registry = &SimpleTest::getRegistry(); + $registry['Parsers'] = $parsers; + } + + /** + * Accessor for global registry of options. + * @return hash All stored values. + */ + protected static function &getRegistry() { + static $registry = false; + if (! $registry) { + $registry = SimpleTest::getDefaults(); + } + return $registry; + } + + /** + * Accessor for the context of the current + * test run. + * @return SimpleTestContext Current test run. + */ + static function getContext() { + static $context = false; + if (! $context) { + $context = new SimpleTestContext(); + } + return $context; + } + + /** + * Constant default values. + * @return hash All registry defaults. + */ + protected static function getDefaults() { + return array( + 'Parsers' => false, + 'MockBaseClass' => 'SimpleMock', + 'IgnoreList' => array(), + 'DefaultProxy' => false, + 'DefaultProxyUsername' => false, + 'DefaultProxyPassword' => false, + 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter())); + } + + /** + * @deprecated + */ + static function setMockBaseClass($mock_base) { + $registry = &SimpleTest::getRegistry(); + $registry['MockBaseClass'] = $mock_base; + } + + /** + * @deprecated + */ + static function getMockBaseClass() { + $registry = &SimpleTest::getRegistry(); + return $registry['MockBaseClass']; + } +} + +/** + * Container for all components for a specific + * test run. Makes things like error queues + * available to PHP event handlers, and also + * gets around some nasty reference issues in + * the mocks. + * @package SimpleTest + */ +class SimpleTestContext { + private $test; + private $reporter; + private $resources; + + /** + * Clears down the current context. + * @access public + */ + function clear() { + $this->resources = array(); + } + + /** + * Sets the current test case instance. This + * global instance can be used by the mock objects + * to send message to the test cases. + * @param SimpleTestCase $test Test case to register. + */ + function setTest($test) { + $this->clear(); + $this->test = $test; + } + + /** + * Accessor for currently running test case. + * @return SimpleTestCase Current test. + */ + function getTest() { + return $this->test; + } + + /** + * Sets the current reporter. This + * global instance can be used by the mock objects + * to send messages. + * @param SimpleReporter $reporter Reporter to register. + */ + function setReporter($reporter) { + $this->clear(); + $this->reporter = $reporter; + } + + /** + * Accessor for current reporter. + * @return SimpleReporter Current reporter. + */ + function getReporter() { + return $this->reporter; + } + + /** + * Accessor for the Singleton resource. + * @return object Global resource. + */ + function get($resource) { + if (! isset($this->resources[$resource])) { + $this->resources[$resource] = new $resource(); + } + return $this->resources[$resource]; + } +} + +/** + * Interrogates the stack trace to recover the + * failure point. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleStackTrace { + private $prefixes; + + /** + * Stashes the list of target prefixes. + * @param array $prefixes List of method prefixes + * to search for. + */ + function __construct($prefixes) { + $this->prefixes = $prefixes; + } + + /** + * Extracts the last method name that was not within + * Simpletest itself. Captures a stack trace if none given. + * @param array $stack List of stack frames. + * @return string Snippet of test report with line + * number and file. + */ + function traceMethod($stack = false) { + $stack = $stack ? $stack : $this->captureTrace(); + foreach ($stack as $frame) { + if ($this->frameLiesWithinSimpleTestFolder($frame)) { + continue; + } + if ($this->frameMatchesPrefix($frame)) { + return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']'; + } + } + return ''; + } + + /** + * Test to see if error is generated by SimpleTest itself. + * @param array $frame PHP stack frame. + * @return boolean True if a SimpleTest file. + */ + protected function frameLiesWithinSimpleTestFolder($frame) { + if (isset($frame['file'])) { + $path = substr(SIMPLE_TEST, 0, -1); + if (strpos($frame['file'], $path) === 0) { + if (dirname($frame['file']) == $path) { + return true; + } + } + } + return false; + } + + /** + * Tries to determine if the method call is an assert, etc. + * @param array $frame PHP stack frame. + * @return boolean True if matches a target. + */ + protected function frameMatchesPrefix($frame) { + foreach ($this->prefixes as $prefix) { + if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) { + return true; + } + } + return false; + } + + /** + * Grabs a current stack trace. + * @return array Fulle trace. + */ + protected function captureTrace() { + if (function_exists('debug_backtrace')) { + return array_reverse(debug_backtrace()); + } + return array(); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/socket.php b/application/libraries/simpletest/socket.php new file mode 100644 index 00000000000..06e8ca62d00 --- /dev/null +++ b/application/libraries/simpletest/socket.php @@ -0,0 +1,312 @@ +clearError(); + } + + /** + * Test for an outstanding error. + * @return boolean True if there is an error. + * @access public + */ + function isError() { + return ($this->error != ''); + } + + /** + * Accessor for an outstanding error. + * @return string Empty string if no error otherwise + * the error message. + * @access public + */ + function getError() { + return $this->error; + } + + /** + * Sets the internal error. + * @param string Error message to stash. + * @access protected + */ + function setError($error) { + $this->error = $error; + } + + /** + * Resets the error state to no error. + * @access protected + */ + function clearError() { + $this->setError(''); + } +} + +/** + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFileSocket extends SimpleStickyError { + private $handle; + private $is_open = false; + private $sent = ''; + private $block_size; + + /** + * Opens a socket for reading and writing. + * @param SimpleUrl $file Target URI to fetch. + * @param integer $block_size Size of chunk to read. + * @access public + */ + function __construct($file, $block_size = 1024) { + parent::__construct(); + if (! ($this->handle = $this->openFile($file, $error))) { + $file_string = $file->asString(); + $this->setError("Cannot open [$file_string] with [$error]"); + return; + } + $this->is_open = true; + $this->block_size = $block_size; + } + + /** + * Writes some data to the socket and saves alocal copy. + * @param string $message String to send to socket. + * @return boolean True if successful. + * @access public + */ + function write($message) { + return true; + } + + /** + * Reads data from the socket. The error suppresion + * is a workaround for PHP4 always throwing a warning + * with a secure socket. + * @return integer/boolean Incoming bytes. False + * on error. + * @access public + */ + function read() { + $raw = @fread($this->handle, $this->block_size); + if ($raw === false) { + $this->setError('Cannot read from socket'); + $this->close(); + } + return $raw; + } + + /** + * Accessor for socket open state. + * @return boolean True if open. + * @access public + */ + function isOpen() { + return $this->is_open; + } + + /** + * Closes the socket preventing further reads. + * Cannot be reopened once closed. + * @return boolean True if successful. + * @access public + */ + function close() { + if (!$this->is_open) return false; + $this->is_open = false; + return fclose($this->handle); + } + + /** + * Accessor for content so far. + * @return string Bytes sent only. + * @access public + */ + function getSent() { + return $this->sent; + } + + /** + * Actually opens the low level socket. + * @param SimpleUrl $file SimpleUrl file target. + * @param string $error Recipient of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + protected function openFile($file, &$error) { + return @fopen($file->asString(), 'r'); + } +} + +/** + * Wrapper for TCP/IP socket. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSocket extends SimpleStickyError { + private $handle; + private $is_open = false; + private $sent = ''; + private $lock_size; + + /** + * Opens a socket for reading and writing. + * @param string $host Hostname to send request to. + * @param integer $port Port on remote machine to open. + * @param integer $timeout Connection timeout in seconds. + * @param integer $block_size Size of chunk to read. + * @access public + */ + function __construct($host, $port, $timeout, $block_size = 255) { + parent::__construct(); + if (! ($this->handle = $this->openSocket($host, $port, $error_number, $error, $timeout))) { + $this->setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds"); + return; + } + $this->is_open = true; + $this->block_size = $block_size; + SimpleTestCompatibility::setTimeout($this->handle, $timeout); + } + + /** + * Writes some data to the socket and saves alocal copy. + * @param string $message String to send to socket. + * @return boolean True if successful. + * @access public + */ + function write($message) { + if ($this->isError() || ! $this->isOpen()) { + return false; + } + $count = fwrite($this->handle, $message); + if (! $count) { + if ($count === false) { + $this->setError('Cannot write to socket'); + $this->close(); + } + return false; + } + fflush($this->handle); + $this->sent .= $message; + return true; + } + + /** + * Reads data from the socket. The error suppresion + * is a workaround for PHP4 always throwing a warning + * with a secure socket. + * @return integer/boolean Incoming bytes. False + * on error. + * @access public + */ + function read() { + if ($this->isError() || ! $this->isOpen()) { + return false; + } + $raw = @fread($this->handle, $this->block_size); + if ($raw === false) { + $this->setError('Cannot read from socket'); + $this->close(); + } + return $raw; + } + + /** + * Accessor for socket open state. + * @return boolean True if open. + * @access public + */ + function isOpen() { + return $this->is_open; + } + + /** + * Closes the socket preventing further reads. + * Cannot be reopened once closed. + * @return boolean True if successful. + * @access public + */ + function close() { + $this->is_open = false; + return fclose($this->handle); + } + + /** + * Accessor for content so far. + * @return string Bytes sent only. + * @access public + */ + function getSent() { + return $this->sent; + } + + /** + * Actually opens the low level socket. + * @param string $host Host to connect to. + * @param integer $port Port on host. + * @param integer $error_number Recipient of error code. + * @param string $error Recipoent of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + protected function openSocket($host, $port, &$error_number, &$error, $timeout) { + return @fsockopen($host, $port, $error_number, $error, $timeout); + } +} + +/** + * Wrapper for TCP/IP socket over TLS. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSecureSocket extends SimpleSocket { + + /** + * Opens a secure socket for reading and writing. + * @param string $host Hostname to send request to. + * @param integer $port Port on remote machine to open. + * @param integer $timeout Connection timeout in seconds. + * @access public + */ + function __construct($host, $port, $timeout) { + parent::__construct($host, $port, $timeout); + } + + /** + * Actually opens the low level socket. + * @param string $host Host to connect to. + * @param integer $port Port on host. + * @param integer $error_number Recipient of error code. + * @param string $error Recipient of error message. + * @param integer $timeout Maximum time to wait for connection. + * @access protected + */ + function openSocket($host, $port, &$error_number, &$error, $timeout) { + return parent::openSocket("tls://$host", $port, $error_number, $error, $timeout); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/tag.php b/application/libraries/simpletest/tag.php new file mode 100644 index 00000000000..afe649ec5dd --- /dev/null +++ b/application/libraries/simpletest/tag.php @@ -0,0 +1,1527 @@ + 'SimpleAnchorTag', + 'title' => 'SimpleTitleTag', + 'base' => 'SimpleBaseTag', + 'button' => 'SimpleButtonTag', + 'textarea' => 'SimpleTextAreaTag', + 'option' => 'SimpleOptionTag', + 'label' => 'SimpleLabelTag', + 'form' => 'SimpleFormTag', + 'frame' => 'SimpleFrameTag'); + $attributes = $this->keysToLowerCase($attributes); + if (array_key_exists($name, $map)) { + $tag_class = $map[$name]; + return new $tag_class($attributes); + } elseif ($name == 'select') { + return $this->createSelectionTag($attributes); + } elseif ($name == 'input') { + return $this->createInputTag($attributes); + } + return new SimpleTag($name, $attributes); + } + + /** + * Factory for selection fields. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + protected function createSelectionTag($attributes) { + if (isset($attributes['multiple'])) { + return new MultipleSelectionTag($attributes); + } + return new SimpleSelectionTag($attributes); + } + + /** + * Factory for input tags. + * @param hash $attributes Element attributes. + * @return SimpleTag Tag object. + * @access protected + */ + protected function createInputTag($attributes) { + if (! isset($attributes['type'])) { + return new SimpleTextTag($attributes); + } + $type = strtolower(trim($attributes['type'])); + $map = array( + 'submit' => 'SimpleSubmitTag', + 'image' => 'SimpleImageSubmitTag', + 'checkbox' => 'SimpleCheckboxTag', + 'radio' => 'SimpleRadioButtonTag', + 'text' => 'SimpleTextTag', + 'hidden' => 'SimpleTextTag', + 'password' => 'SimpleTextTag', + 'file' => 'SimpleUploadTag'); + if (array_key_exists($type, $map)) { + $tag_class = $map[$type]; + return new $tag_class($attributes); + } + return false; + } + + /** + * Make the keys lower case for case insensitive look-ups. + * @param hash $map Hash to convert. + * @return hash Unchanged values, but keys lower case. + * @access private + */ + protected function keysToLowerCase($map) { + $lower = array(); + foreach ($map as $key => $value) { + $lower[strtolower($key)] = $value; + } + return $lower; + } +} + +/** + * HTML or XML tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTag { + private $name; + private $attributes; + private $content; + + /** + * Starts with a named tag with attributes only. + * @param string $name Tag name. + * @param hash $attributes Attribute names and + * string values. Note that + * the keys must have been + * converted to lower case. + */ + function __construct($name, $attributes) { + $this->name = strtolower(trim($name)); + $this->attributes = $attributes; + $this->content = ''; + } + + /** + * Check to see if the tag can have both start and + * end tags with content in between. + * @return boolean True if content allowed. + * @access public + */ + function expectEndTag() { + return true; + } + + /** + * The current tag should not swallow all content for + * itself as it's searchable page content. Private + * content tags are usually widgets that contain default + * values. + * @return boolean False as content is available + * to other tags by default. + * @access public + */ + function isPrivateContent() { + return false; + } + + /** + * Appends string content to the current content. + * @param string $content Additional text. + * @access public + */ + function addContent($content) { + $this->content .= (string)$content; + return $this; + } + + /** + * Adds an enclosed tag to the content. + * @param SimpleTag $tag New tag. + * @access public + */ + function addTag($tag) { + } + + /** + * Adds multiple enclosed tags to the content. + * @param array List of SimpleTag objects to be added. + */ + function addTags($tags) { + foreach ($tags as $tag) { + $this->addTag($tag); + } + } + + /** + * Accessor for tag name. + * @return string Name of tag. + * @access public + */ + function getTagName() { + return $this->name; + } + + /** + * List of legal child elements. + * @return array List of element names. + * @access public + */ + function getChildElements() { + return array(); + } + + /** + * Accessor for an attribute. + * @param string $label Attribute name. + * @return string Attribute value. + * @access public + */ + function getAttribute($label) { + $label = strtolower($label); + if (! isset($this->attributes[$label])) { + return false; + } + return (string)$this->attributes[$label]; + } + + /** + * Sets an attribute. + * @param string $label Attribute name. + * @return string $value New attribute value. + * @access protected + */ + protected function setAttribute($label, $value) { + $this->attributes[strtolower($label)] = $value; + } + + /** + * Accessor for the whole content so far. + * @return string Content as big raw string. + * @access public + */ + function getContent() { + return $this->content; + } + + /** + * Accessor for content reduced to visible text. Acts + * like a text mode browser, normalising space and + * reducing images to their alt text. + * @return string Content as plain text. + * @access public + */ + function getText() { + return SimplePage::normalise($this->content); + } + + /** + * Test to see if id attribute matches. + * @param string $id ID to test against. + * @return boolean True on match. + * @access public + */ + function isId($id) { + return ($this->getAttribute('id') == $id); + } +} + +/** + * Base url. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleBaseTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('base', $attributes); + } + + /** + * Base tag is not a block tag. + * @return boolean false + * @access public + */ + function expectEndTag() { + return false; + } +} + +/** + * Page title. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTitleTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('title', $attributes); + } +} + +/** + * Link. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleAnchorTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('a', $attributes); + } + + /** + * Accessor for URL as string. + * @return string Coerced as string. + * @access public + */ + function getHref() { + $url = $this->getAttribute('href'); + if (is_bool($url)) { + $url = ''; + } + return $url; + } +} + +/** + * Form element. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleWidget extends SimpleTag { + private $value; + private $label; + private $is_set; + + /** + * Starts with a named tag with attributes only. + * @param string $name Tag name. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($name, $attributes) { + parent::__construct($name, $attributes); + $this->value = false; + $this->label = false; + $this->is_set = false; + } + + /** + * Accessor for name submitted as the key in + * GET/POST privateiables hash. + * @return string Parsed value. + * @access public + */ + function getName() { + return $this->getAttribute('name'); + } + + /** + * Accessor for default value parsed with the tag. + * @return string Parsed value. + * @access public + */ + function getDefault() { + return $this->getAttribute('value'); + } + + /** + * Accessor for currently set value or default if + * none. + * @return string Value set by form or default + * if none. + * @access public + */ + function getValue() { + if (! $this->is_set) { + return $this->getDefault(); + } + return $this->value; + } + + /** + * Sets the current form element value. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + $this->value = $value; + $this->is_set = true; + return true; + } + + /** + * Resets the form element value back to the + * default. + * @access public + */ + function resetValue() { + $this->is_set = false; + } + + /** + * Allows setting of a label externally, say by a + * label tag. + * @param string $label Label to attach. + * @access public + */ + function setLabel($label) { + $this->label = trim($label); + return $this; + } + + /** + * Reads external or internal label. + * @param string $label Label to test. + * @return boolean True is match. + * @access public + */ + function isLabel($label) { + return $this->label == trim($label); + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + if ($this->getName()) { + $encoding->add($this->getName(), $this->getValue()); + } + } +} + +/** + * Text, password and hidden field. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTextTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', ''); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Sets the current form element value. Cannot + * change the value of a hidden field. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($this->getAttribute('type') == 'hidden') { + return false; + } + return parent::setValue($value); + } +} + +/** + * Submit button as input tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSubmitTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'Submit'); + } + } + + /** + * Tag contains no end element. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + return $this->getValue(); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } +} + +/** + * Image button as input tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleImageSubmitTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + } + + /** + * Tag contains no end element. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + if ($this->getAttribute('title')) { + return $this->getAttribute('title'); + } + return $this->getAttribute('alt'); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @param integer $x X coordinate of click. + * @param integer $y Y coordinate of click. + * @access public + */ + function write($encoding, $x = 1, $y = 1) { + if ($this->getName()) { + $encoding->add($this->getName() . '.x', $x); + $encoding->add($this->getName() . '.y', $y); + } else { + $encoding->add('x', $x); + $encoding->add('y', $y); + } + } +} + +/** + * Submit button as button tag. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleButtonTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * Defaults are very browser dependent. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('button', $attributes); + } + + /** + * Check to see if the tag can have both start and + * end tags with content in between. + * @return boolean True if content allowed. + * @access public + */ + function expectEndTag() { + return true; + } + + /** + * Disables the setting of the button value. + * @param string $value Ignored. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Value of browser visible text. + * @return string Visible label. + * @access public + */ + function getLabel() { + return $this->getContent(); + } + + /** + * Test for a label match when searching. + * @param string $label Label to test. + * @return boolean True on match. + * @access public + */ + function isLabel($label) { + return trim($label) == trim($this->getLabel()); + } +} + +/** + * Content tag for text area. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTextAreaTag extends SimpleWidget { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('textarea', $attributes); + } + + /** + * Accessor for starting value. + * @return string Parsed value. + * @access public + */ + function getDefault() { + return $this->wrap(html_entity_decode($this->getContent(), ENT_QUOTES)); + } + + /** + * Applies word wrapping if needed. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + return parent::setValue($this->wrap($value)); + } + + /** + * Test to see if text should be wrapped. + * @return boolean True if wrapping on. + * @access private + */ + function wrapIsEnabled() { + if ($this->getAttribute('cols')) { + $wrap = $this->getAttribute('wrap'); + if (($wrap == 'physical') || ($wrap == 'hard')) { + return true; + } + } + return false; + } + + /** + * Performs the formatting that is peculiar to + * this tag. There is strange behaviour in this + * one, including stripping a leading new line. + * Go figure. I am using Firefox as a guide. + * @param string $text Text to wrap. + * @return string Text wrapped with carriage + * returns and line feeds + * @access private + */ + protected function wrap($text) { + $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text)); + $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text)); + if (strncmp($text, "\r\n", strlen("\r\n")) == 0) { + $text = substr($text, strlen("\r\n")); + } + if ($this->wrapIsEnabled()) { + return wordwrap( + $text, + (integer)$this->getAttribute('cols'), + "\r\n"); + } + return $text; + } + + /** + * The content of textarea is not part of the page. + * @return boolean True. + * @access public + */ + function isPrivateContent() { + return true; + } +} + +/** + * File upload widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleUploadTag extends SimpleWidget { + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + if (! file_exists($this->getValue())) { + return; + } + $encoding->attach( + $this->getName(), + implode('', file($this->getValue())), + basename($this->getValue())); + } +} + +/** + * Drop down widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleSelectionTag extends SimpleWidget { + private $options; + private $choice; + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('select', $attributes); + $this->options = array(); + $this->choice = false; + } + + /** + * Adds an option tag to a selection field. + * @param SimpleOptionTag $tag New option. + * @access public + */ + function addTag($tag) { + if ($tag->getTagName() == 'option') { + $this->options[] = $tag; + } + } + + /** + * Text within the selection element is ignored. + * @param string $content Ignored. + * @access public + */ + function addContent($content) { + return $this; + } + + /** + * Scans options for defaults. If none, then + * the first option is selected. + * @return string Selected field. + * @access public + */ + function getDefault() { + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->getAttribute('selected') !== false) { + return $this->options[$i]->getDefault(); + } + } + if ($count > 0) { + return $this->options[0]->getDefault(); + } + return ''; + } + + /** + * Can only set allowed values. + * @param string $value New choice. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->isValue($value)) { + $this->choice = $i; + return true; + } + } + return false; + } + + /** + * Accessor for current selection value. + * @return string Value attribute or + * content of opton. + * @access public + */ + function getValue() { + if ($this->choice === false) { + return $this->getDefault(); + } + return $this->options[$this->choice]->getValue(); + } +} + +/** + * Drop down widget. + * @package SimpleTest + * @subpackage WebTester + */ +class MultipleSelectionTag extends SimpleWidget { + private $options; + private $values; + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('select', $attributes); + $this->options = array(); + $this->values = false; + } + + /** + * Adds an option tag to a selection field. + * @param SimpleOptionTag $tag New option. + * @access public + */ + function addTag($tag) { + if ($tag->getTagName() == 'option') { + $this->options[] = &$tag; + } + } + + /** + * Text within the selection element is ignored. + * @param string $content Ignored. + * @access public + */ + function addContent($content) { + return $this; + } + + /** + * Scans options for defaults to populate the + * value array(). + * @return array Selected fields. + * @access public + */ + function getDefault() { + $default = array(); + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->getAttribute('selected') !== false) { + $default[] = $this->options[$i]->getDefault(); + } + } + return $default; + } + + /** + * Can only set allowed values. Any illegal value + * will result in a failure, but all correct values + * will be set. + * @param array $desired New choices. + * @return boolean True if all allowed. + * @access public + */ + function setValue($desired) { + $achieved = array(); + foreach ($desired as $value) { + $success = false; + for ($i = 0, $count = count($this->options); $i < $count; $i++) { + if ($this->options[$i]->isValue($value)) { + $achieved[] = $this->options[$i]->getValue(); + $success = true; + break; + } + } + if (! $success) { + return false; + } + } + $this->values = $achieved; + return true; + } + + /** + * Accessor for current selection value. + * @return array List of currently set options. + * @access public + */ + function getValue() { + if ($this->values === false) { + return $this->getDefault(); + } + return $this->values; + } +} + +/** + * Option for selection field. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleOptionTag extends SimpleWidget { + + /** + * Stashes the attributes. + */ + function __construct($attributes) { + parent::__construct('option', $attributes); + } + + /** + * Does nothing. + * @param string $value Ignored. + * @return boolean Not allowed. + * @access public + */ + function setValue($value) { + return false; + } + + /** + * Test to see if a value matches the option. + * @param string $compare Value to compare with. + * @return boolean True if possible match. + * @access public + */ + function isValue($compare) { + $compare = trim($compare); + if (trim($this->getValue()) == $compare) { + return true; + } + return trim(strip_tags($this->getContent())) == $compare; + } + + /** + * Accessor for starting value. Will be set to + * the option label if no value exists. + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('value') === false) { + return strip_tags($this->getContent()); + } + return $this->getAttribute('value'); + } + + /** + * The content of options is not part of the page. + * @return boolean True. + * @access public + */ + function isPrivateContent() { + return true; + } +} + +/** + * Radio button. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleRadioButtonTag extends SimpleWidget { + + /** + * Stashes the attributes. + * @param array $attributes Hash of attributes. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'on'); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * The only allowed value sn the one in the + * "value" attribute. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($value === false) { + return parent::setValue($value); + } + if ($value != $this->getAttribute('value')) { + return false; + } + return parent::setValue($value); + } + + /** + * Accessor for starting value. + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('checked') !== false) { + return $this->getAttribute('value'); + } + return false; + } +} + +/** + * Checkbox widget. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleCheckboxTag extends SimpleWidget { + + /** + * Starts with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('input', $attributes); + if ($this->getAttribute('value') === false) { + $this->setAttribute('value', 'on'); + } + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } + + /** + * The only allowed value in the one in the + * "value" attribute. The default for this + * attribute is "on". If this widget is set to + * true, then the usual value will be taken. + * @param string $value New value. + * @return boolean True if allowed. + * @access public + */ + function setValue($value) { + if ($value === false) { + return parent::setValue($value); + } + if ($value === true) { + return parent::setValue($this->getAttribute('value')); + } + if ($value != $this->getAttribute('value')) { + return false; + } + return parent::setValue($value); + } + + /** + * Accessor for starting value. The default + * value is "on". + * @return string Parsed value. + * @access public + */ + function getDefault() { + if ($this->getAttribute('checked') !== false) { + return $this->getAttribute('value'); + } + return false; + } +} + +/** + * A group of multiple widgets with some shared behaviour. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleTagGroup { + private $widgets = array(); + + /** + * Adds a tag to the group. + * @param SimpleWidget $widget + * @access public + */ + function addWidget($widget) { + $this->widgets[] = $widget; + } + + /** + * Accessor to widget set. + * @return array All widgets. + * @access protected + */ + protected function &getWidgets() { + return $this->widgets; + } + + /** + * Accessor for an attribute. + * @param string $label Attribute name. + * @return boolean Always false. + * @access public + */ + function getAttribute($label) { + return false; + } + + /** + * Fetches the name for the widget from the first + * member. + * @return string Name of widget. + * @access public + */ + function getName() { + if (count($this->widgets) > 0) { + return $this->widgets[0]->getName(); + } + } + + /** + * Scans the widgets for one with the appropriate + * ID field. + * @param string $id ID value to try. + * @return boolean True if matched. + * @access public + */ + function isId($id) { + for ($i = 0, $count = count($this->widgets); $i < $count; $i++) { + if ($this->widgets[$i]->isId($id)) { + return true; + } + } + return false; + } + + /** + * Scans the widgets for one with the appropriate + * attached label. + * @param string $label Attached label to try. + * @return boolean True if matched. + * @access public + */ + function isLabel($label) { + for ($i = 0, $count = count($this->widgets); $i < $count; $i++) { + if ($this->widgets[$i]->isLabel($label)) { + return true; + } + } + return false; + } + + /** + * Dispatches the value into the form encoded packet. + * @param SimpleEncoding $encoding Form packet. + * @access public + */ + function write($encoding) { + $encoding->add($this->getName(), $this->getValue()); + } +} + +/** + * A group of tags with the same name within a form. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleCheckboxGroup extends SimpleTagGroup { + + /** + * Accessor for current selected widget or false + * if none. + * @return string/array Widget values or false if none. + * @access public + */ + function getValue() { + $values = array(); + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getValue() !== false) { + $values[] = $widgets[$i]->getValue(); + } + } + return $this->coerceValues($values); + } + + /** + * Accessor for starting value that is active. + * @return string/array Widget values or false if none. + * @access public + */ + function getDefault() { + $values = array(); + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getDefault() !== false) { + $values[] = $widgets[$i]->getDefault(); + } + } + return $this->coerceValues($values); + } + + /** + * Accessor for current set values. + * @param string/array/boolean $values Either a single string, a + * hash or false for nothing set. + * @return boolean True if all values can be set. + * @access public + */ + function setValue($values) { + $values = $this->makeArray($values); + if (! $this->valuesArePossible($values)) { + return false; + } + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + $possible = $widgets[$i]->getAttribute('value'); + if (in_array($widgets[$i]->getAttribute('value'), $values)) { + $widgets[$i]->setValue($possible); + } else { + $widgets[$i]->setValue(false); + } + } + return true; + } + + /** + * Tests to see if a possible value set is legal. + * @param string/array/boolean $values Either a single string, a + * hash or false for nothing set. + * @return boolean False if trying to set a + * missing value. + * @access private + */ + protected function valuesArePossible($values) { + $matches = array(); + $widgets = &$this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + $possible = $widgets[$i]->getAttribute('value'); + if (in_array($possible, $values)) { + $matches[] = $possible; + } + } + return ($values == $matches); + } + + /** + * Converts the output to an appropriate format. This means + * that no values is false, a single value is just that + * value and only two or more are contained in an array. + * @param array $values List of values of widgets. + * @return string/array/boolean Expected format for a tag. + * @access private + */ + protected function coerceValues($values) { + if (count($values) == 0) { + return false; + } elseif (count($values) == 1) { + return $values[0]; + } else { + return $values; + } + } + + /** + * Converts false or string into array. The opposite of + * the coercian method. + * @param string/array/boolean $value A single item is converted + * to a one item list. False + * gives an empty list. + * @return array List of values, possibly empty. + * @access private + */ + protected function makeArray($value) { + if ($value === false) { + return array(); + } + if (is_string($value)) { + return array($value); + } + return $value; + } +} + +/** + * A group of tags with the same name within a form. + * Used for radio buttons. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleRadioGroup extends SimpleTagGroup { + + /** + * Each tag is tried in turn until one is + * successfully set. The others will be + * unchecked if successful. + * @param string $value New value. + * @return boolean True if any allowed. + * @access public + */ + function setValue($value) { + if (! $this->valueIsPossible($value)) { + return false; + } + $index = false; + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if (! $widgets[$i]->setValue($value)) { + $widgets[$i]->setValue(false); + } + } + return true; + } + + /** + * Tests to see if a value is allowed. + * @param string Attempted value. + * @return boolean True if a valid value. + * @access private + */ + protected function valueIsPossible($value) { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getAttribute('value') == $value) { + return true; + } + } + return false; + } + + /** + * Accessor for current selected widget or false + * if none. + * @return string/boolean Value attribute or + * content of opton. + * @access public + */ + function getValue() { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getValue() !== false) { + return $widgets[$i]->getValue(); + } + } + return false; + } + + /** + * Accessor for starting value that is active. + * @return string/boolean Value of first checked + * widget or false if none. + * @access public + */ + function getDefault() { + $widgets = $this->getWidgets(); + for ($i = 0, $count = count($widgets); $i < $count; $i++) { + if ($widgets[$i]->getDefault() !== false) { + return $widgets[$i]->getDefault(); + } + } + return false; + } +} + +/** + * Tag to keep track of labels. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleLabelTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('label', $attributes); + } + + /** + * Access for the ID to attach the label to. + * @return string For attribute. + * @access public + */ + function getFor() { + return $this->getAttribute('for'); + } +} + +/** + * Tag to aid parsing the form. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFormTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('form', $attributes); + } +} + +/** + * Tag to aid parsing the frames in a page. + * @package SimpleTest + * @subpackage WebTester + */ +class SimpleFrameTag extends SimpleTag { + + /** + * Starts with a named tag with attributes only. + * @param hash $attributes Attribute names and + * string values. + */ + function __construct($attributes) { + parent::__construct('frame', $attributes); + } + + /** + * Tag contains no content. + * @return boolean False. + * @access public + */ + function expectEndTag() { + return false; + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/acceptance_test.php b/application/libraries/simpletest/test/acceptance_test.php new file mode 100644 index 00000000000..e96fe737e5f --- /dev/null +++ b/application/libraries/simpletest/test/acceptance_test.php @@ -0,0 +1,1729 @@ +addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $this->assertTrue($browser->get($this->samples() . 'network_confirm.php')); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + $this->assertPattern('/Request method.*?
    GET<\/dd>/', $browser->getContent()); + $this->assertEqual($browser->getTitle(), 'Simple test target file'); + $this->assertEqual($browser->getResponseCode(), 200); + $this->assertEqual($browser->getMimeType(), 'text/html'); + } + + function testPost() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $this->assertTrue($browser->post($this->samples() . 'network_confirm.php')); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + $this->assertPattern('/Request method.*?
    POST<\/dd>/', $browser->getContent()); + } + + function testAbsoluteLinkFollowing() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($browser->clickLink('Absolute')); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + } + + function testRelativeEncodedLinkFollowing() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'link_confirm.php'); + // Warning: the below data is ISO 8859-1 encoded + $this->assertTrue($browser->clickLink("m\xE4rc\xEAl kiek'eboe")); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + } + + function testRelativeLinkFollowing() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($browser->clickLink('Relative')); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + } + + function testUnifiedClickLinkClicking() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($browser->click('Relative')); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + } + + function testIdLinkFollowing() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($browser->clickLinkById(1)); + $this->assertPattern('/target for the SimpleTest/', $browser->getContent()); + } + + function testCookieReading() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'set_cookies.php'); + $this->assertEqual($browser->getCurrentCookieValue('session_cookie'), 'A'); + $this->assertEqual($browser->getCurrentCookieValue('short_cookie'), 'B'); + $this->assertEqual($browser->getCurrentCookieValue('day_cookie'), 'C'); + } + + function testSimpleSubmit() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'form.html'); + $this->assertTrue($browser->clickSubmit('Go!')); + $this->assertPattern('/Request method.*?
    POST<\/dd>/', $browser->getContent()); + $this->assertPattern('/go=\[Go!\]/', $browser->getContent()); + } + + function testUnifiedClickCanSubmit() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $browser->get($this->samples() . 'form.html'); + $this->assertTrue($browser->click('Go!')); + $this->assertPattern('/go=\[Go!\]/', $browser->getContent()); + } +} + +class TestOfLocalFileBrowser extends UnitTestCase { + function samples() { + return 'file://'.dirname(__FILE__).'/site/'; + } + + function testGet() { + $browser = new SimpleBrowser(); + $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + $this->assertTrue($browser->get($this->samples() . 'file.html')); + $this->assertPattern('/Link to SimpleTest/', $browser->getContent()); + $this->assertEqual($browser->getTitle(), 'Link to SimpleTest'); + $this->assertFalse($browser->getResponseCode()); + $this->assertEqual($browser->getMimeType(), ''); + } +} + +class TestOfRequestMethods extends UnitTestCase { + function samples() { + return SimpleTestAcceptanceTest::samples(); + } + + function testHeadRequest() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->head($this->samples() . 'request_methods.php')); + $this->assertEqual($browser->getResponseCode(), 202); + } + + function testGetRequest() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->get($this->samples() . 'request_methods.php')); + $this->assertEqual($browser->getResponseCode(), 405); + } + + function testPostWithPlainEncoding() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->post($this->samples() . 'request_methods.php', 'A content message')); + $this->assertEqual($browser->getResponseCode(), 406); + $this->assertPattern('/Please ensure content type is an XML format/', $browser->getContent()); + } + + function testPostWithXmlEncoding() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->post($this->samples() . 'request_methods.php', 'c', 'text/xml')); + $this->assertEqual($browser->getResponseCode(), 201); + $this->assertPattern('/c/', $browser->getContent()); + } + + function testPutWithPlainEncoding() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->put($this->samples() . 'request_methods.php', 'A content message')); + $this->assertEqual($browser->getResponseCode(), 406); + $this->assertPattern('/Please ensure content type is an XML format/', $browser->getContent()); + } + + function testPutWithXmlEncoding() { + $browser = new SimpleBrowser(); + $this->assertTrue($browser->put($this->samples() . 'request_methods.php', 'c', 'application/xml')); + $this->assertEqual($browser->getResponseCode(), 201); + $this->assertPattern('/c/', $browser->getContent()); + } + + function testDeleteRequest() { + $browser = new SimpleBrowser(); + $browser->delete($this->samples() . 'request_methods.php'); + $this->assertEqual($browser->getResponseCode(), 202); + $this->assertPattern('/Your delete request was accepted/', $browser->getContent()); + } + +} + +class TestRadioFields extends SimpleTestAcceptanceTest { + function testSetFieldAsInteger() { + $this->get($this->samples() . 'form_with_radio_buttons.html'); + $this->assertTrue($this->setField('tested_field', 2)); + $this->clickSubmitByName('send'); + $this->assertEqual($this->getUrl(), $this->samples() . 'form_with_radio_buttons.html?tested_field=2&send=click+me'); + } + + function testSetFieldAsString() { + $this->get($this->samples() . 'form_with_radio_buttons.html'); + $this->assertTrue($this->setField('tested_field', '2')); + $this->clickSubmitByName('send'); + $this->assertEqual($this->getUrl(), $this->samples() . 'form_with_radio_buttons.html?tested_field=2&send=click+me'); + } +} + +class TestOfLiveFetching extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testFormWithArrayBasedInputs() { + $this->get($this->samples() . 'form_with_array_based_inputs.php'); + $this->setField('value[]', '3', '1'); + $this->setField('value[]', '4', '2'); + $this->clickSubmit('Go'); + $this->assertPattern('/QUERY_STRING : value%5B%5D=3&value%5B%5D=4&submit=Go/'); + } + + function testFormWithQuotedValues() { + $this->get($this->samples() . 'form_with_quoted_values.php'); + $this->assertField('a', 'default'); + $this->assertFieldById('text_field', 'default'); + $this->clickSubmit('Go'); + $this->assertPattern('/a=default&submit=Go/'); + } + + function testGet() { + $this->assertTrue($this->get($this->samples() . 'network_confirm.php')); + $this->assertEqual($this->getUrl(), $this->samples() . 'network_confirm.php'); + $this->assertText('target for the SimpleTest'); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertTitle('Simple test target file'); + $this->assertTitle(new PatternExpectation('/target file/')); + $this->assertResponse(200); + $this->assertMime('text/html'); + $this->assertHeader('connection', 'close'); + $this->assertHeader('connection', new PatternExpectation('/los/')); + } + + function testSlowGet() { + $this->assertTrue($this->get($this->samples() . 'slow_page.php')); + } + + function testTimedOutGet() { + $this->setConnectionTimeout(1); + $this->ignoreErrors(); + $this->assertFalse($this->get($this->samples() . 'slow_page.php')); + } + + function testPost() { + $this->assertTrue($this->post($this->samples() . 'network_confirm.php')); + $this->assertText('target for the SimpleTest'); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + } + + function testGetWithData() { + $this->get($this->samples() . 'network_confirm.php', array("a" => "aaa")); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[aaa]'); + } + + function testPostWithData() { + $this->post($this->samples() . 'network_confirm.php', array("a" => "aaa")); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aaa]'); + } + + function testPostWithRecursiveData() { + $this->post($this->samples() . 'network_confirm.php', array("a" => "aaa")); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aaa]'); + + $this->post($this->samples() . 'network_confirm.php', array("a[aa]" => "aaa")); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aa=[aaa]]'); + + $this->post($this->samples() . 'network_confirm.php', array("a[aa][aaa]" => "aaaa")); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aa=[aaa=[aaaa]]]'); + + $this->post($this->samples() . 'network_confirm.php', array("a" => array("aa" => "aaa"))); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aa=[aaa]]'); + + $this->post($this->samples() . 'network_confirm.php', array("a" => array("aa" => array("aaa" => "aaaa")))); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aa=[aaa=[aaaa]]]'); + } + + function testRelativeGet() { + $this->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($this->get('network_confirm.php')); + $this->assertText('target for the SimpleTest'); + } + + function testRelativePost() { + $this->post($this->samples() . 'link_confirm.php', array('a' => '123')); + $this->assertTrue($this->post('network_confirm.php')); + $this->assertText('target for the SimpleTest'); + } +} + +class TestOfLinkFollowing extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testLinkAssertions() { + $this->get($this->samples() . 'link_confirm.php'); + $this->assertLink('Absolute', $this->samples() . 'network_confirm.php'); + $this->assertLink('Absolute', new PatternExpectation('/confirm/')); + $this->assertClickable('Absolute'); + } + + function testAbsoluteLinkFollowing() { + $this->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($this->clickLink('Absolute')); + $this->assertText('target for the SimpleTest'); + } + + function testRelativeLinkFollowing() { + $this->get($this->samples() . 'link_confirm.php'); + $this->assertTrue($this->clickLink('Relative')); + $this->assertText('target for the SimpleTest'); + } + + function testLinkIdFollowing() { + $this->get($this->samples() . 'link_confirm.php'); + $this->assertLinkById(1); + $this->assertTrue($this->clickLinkById(1)); + $this->assertText('target for the SimpleTest'); + } + + function testAbsoluteUrlBehavesAbsolutely() { + $this->get($this->samples() . 'link_confirm.php'); + $this->get('http://www.lastcraft.com'); + $this->assertText('No guarantee of quality is given or even intended'); + } + + function testRelativeUrlRespectsBaseTag() { + $this->get($this->samples() . 'base_tag/base_link.html'); + $this->click('Back to test pages'); + $this->assertTitle('Simple test target file'); + } +} + +class TestOfLivePageLinkingWithMinimalLinks extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testClickToExplicitelyNamedSelfReturns() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->assertEqual($this->getUrl(), $this->samples() . 'front_controller_style/a_page.php'); + $this->assertTitle('Simple test page with links'); + $this->assertLink('Self'); + $this->clickLink('Self'); + $this->assertTitle('Simple test page with links'); + } + + function testClickToMissingPageReturnsToSamePage() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->clickLink('No page'); + $this->assertTitle('Simple test page with links'); + $this->assertText('[action=no_page]'); + } + + function testClickToBareActionReturnsToSamePage() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->clickLink('Bare action'); + $this->assertTitle('Simple test page with links'); + $this->assertText('[action=]'); + } + + function testClickToSingleQuestionMarkReturnsToSamePage() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->clickLink('Empty query'); + $this->assertTitle('Simple test page with links'); + } + + function testClickToEmptyStringReturnsToSamePage() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->clickLink('Empty link'); + $this->assertTitle('Simple test page with links'); + } + + function testClickToSingleDotGoesToCurrentDirectory() { + $this->get($this->samples() . 'front_controller_style/a_page.php'); + $this->clickLink('Current directory'); + $this->assertTitle( + 'Simple test front controller', + '%s -> index.php needs to be set as a default web server home page'); + } + + function testClickBackADirectoryLevel() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('Down one'); + $this->assertPattern('|Index of .*?/test|i'); + } +} + +class TestOfLiveFrontControllerEmulation extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testJumpToNamedPage() { + $this->get($this->samples() . 'front_controller_style/'); + $this->assertText('Simple test front controller'); + $this->clickLink('Index'); + $this->assertResponse(200); + $this->assertText('[action=index]'); + } + + function testJumpToUnnamedPage() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('No page'); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + $this->assertText('[action=no_page]'); + } + + function testJumpToUnnamedPageWithBareParameter() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('Bare action'); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + $this->assertText('[action=]'); + } + + function testJumpToUnnamedPageWithEmptyQuery() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('Empty query'); + $this->assertResponse(200); + $this->assertPattern('/Simple test front controller/'); + $this->assertPattern('/raw get data.*?\[\].*?get data/si'); + } + + function testJumpToUnnamedPageWithEmptyLink() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('Empty link'); + $this->assertResponse(200); + $this->assertPattern('/Simple test front controller/'); + $this->assertPattern('/raw get data.*?\[\].*?get data/si'); + } + + function testJumpBackADirectoryLevel() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickLink('Down one'); + $this->assertPattern('|Index of .*?/test|'); + } + + function testSubmitToNamedPage() { + $this->get($this->samples() . 'front_controller_style/'); + $this->assertText('Simple test front controller'); + $this->clickSubmit('Index'); + $this->assertResponse(200); + $this->assertText('[action=Index]'); + } + + function testSubmitToSameDirectory() { + $this->get($this->samples() . 'front_controller_style/index.php'); + $this->clickSubmit('Same directory'); + $this->assertResponse(200); + $this->assertText('[action=Same+directory]'); + } + + function testSubmitToEmptyAction() { + $this->get($this->samples() . 'front_controller_style/index.php'); + $this->clickSubmit('Empty action'); + $this->assertResponse(200); + $this->assertText('[action=Empty+action]'); + } + + function testSubmitToNoAction() { + $this->get($this->samples() . 'front_controller_style/index.php'); + $this->clickSubmit('No action'); + $this->assertResponse(200); + $this->assertText('[action=No+action]'); + } + + function testSubmitBackADirectoryLevel() { + $this->get($this->samples() . 'front_controller_style/'); + $this->clickSubmit('Down one'); + $this->assertPattern('|Index of .*?/test|'); + } + + function testSubmitToNamedPageWithMixedPostAndGet() { + $this->get($this->samples() . 'front_controller_style/?a=A'); + $this->assertText('Simple test front controller'); + $this->clickSubmit('Index post'); + $this->assertText('action=[Index post]'); + $this->assertNoText('[a=A]'); + } + + function testSubmitToSameDirectoryMixedPostAndGet() { + $this->get($this->samples() . 'front_controller_style/index.php?a=A'); + $this->clickSubmit('Same directory post'); + $this->assertText('action=[Same directory post]'); + $this->assertNoText('[a=A]'); + } + + function testSubmitToEmptyActionMixedPostAndGet() { + $this->get($this->samples() . 'front_controller_style/index.php?a=A'); + $this->clickSubmit('Empty action post'); + $this->assertText('action=[Empty action post]'); + $this->assertText('[a=A]'); + } + + function testSubmitToNoActionMixedPostAndGet() { + $this->get($this->samples() . 'front_controller_style/index.php?a=A'); + $this->clickSubmit('No action post'); + $this->assertText('action=[No action post]'); + $this->assertText('[a=A]'); + } +} + +class TestOfLiveHeaders extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testConfirmingHeaderExistence() { + $this->get('http://www.lastcraft.com/'); + $this->assertHeader('content-type'); + $this->assertHeader('content-type', 'text/html'); + $this->assertHeader('content-type', new PatternExpectation('/HTML/i')); + $this->assertNoHeader('WWW-Authenticate'); + } +} + +class TestOfLiveRedirects extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testNoRedirects() { + $this->setMaximumRedirects(0); + $this->get($this->samples() . 'redirect.php'); + $this->assertTitle('Redirection test'); + } + + function testRedirects() { + $this->setMaximumRedirects(1); + $this->get($this->samples() . 'redirect.php'); + $this->assertTitle('Simple test target file'); + } + + function testRedirectLosesGetData() { + $this->get($this->samples() . 'redirect.php', array('a' => 'aaa')); + $this->assertNoText('a=[aaa]'); + } + + function testRedirectKeepsExtraRequestDataOfItsOwn() { + $this->get($this->samples() . 'redirect.php'); + $this->assertText('r=[rrr]'); + } + + function testRedirectLosesPostData() { + $this->post($this->samples() . 'redirect.php', array('a' => 'aaa')); + $this->assertTitle('Simple test target file'); + $this->assertNoText('a=[aaa]'); + } + + function testRedirectWithBaseUrlChange() { + $this->get($this->samples() . 'base_change_redirect.php'); + $this->assertTitle('Simple test target file in folder'); + $this->get($this->samples() . 'path/base_change_redirect.php'); + $this->assertTitle('Simple test target file'); + } + + function testRedirectWithDoubleBaseUrlChange() { + $this->get($this->samples() . 'double_base_change_redirect.php'); + $this->assertTitle('Simple test target file'); + } +} + +class TestOfLiveCookies extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function here() { + return new SimpleUrl($this->samples()); + } + + function thisHost() { + $here = $this->here(); + return $here->getHost(); + } + + function thisPath() { + $here = $this->here(); + return $here->getPath(); + } + + function testCookieSettingAndAssertions() { + $this->setCookie('a', 'Test cookie a'); + $this->setCookie('b', 'Test cookie b', $this->thisHost()); + $this->setCookie('c', 'Test cookie c', $this->thisHost(), $this->thisPath()); + $this->get($this->samples() . 'network_confirm.php'); + $this->assertText('Test cookie a'); + $this->assertText('Test cookie b'); + $this->assertText('Test cookie c'); + $this->assertCookie('a'); + $this->assertCookie('b', 'Test cookie b'); + $this->assertTrue($this->getCookie('c') == 'Test cookie c'); + } + + function testNoCookieSetWhenCookiesDisabled() { + $this->setCookie('a', 'Test cookie a'); + $this->ignoreCookies(); + $this->get($this->samples() . 'network_confirm.php'); + $this->assertNoText('Test cookie a'); + } + + function testCookieReading() { + $this->get($this->samples() . 'set_cookies.php'); + $this->assertCookie('session_cookie', 'A'); + $this->assertCookie('short_cookie', 'B'); + $this->assertCookie('day_cookie', 'C'); + } + + function testNoCookie() { + $this->assertNoCookie('aRandomCookie'); + } + + function testNoCookieReadingWhenCookiesDisabled() { + $this->ignoreCookies(); + $this->get($this->samples() . 'set_cookies.php'); + $this->assertNoCookie('session_cookie'); + $this->assertNoCookie('short_cookie'); + $this->assertNoCookie('day_cookie'); + } + + function testCookiePatternAssertions() { + $this->get($this->samples() . 'set_cookies.php'); + $this->assertCookie('session_cookie', new PatternExpectation('/a/i')); + } + + function testTemporaryCookieExpiry() { + $this->get($this->samples() . 'set_cookies.php'); + $this->restart(); + $this->assertNoCookie('session_cookie'); + $this->assertCookie('day_cookie', 'C'); + } + + function testTimedCookieExpiryWith100SecondMargin() { + $this->get($this->samples() . 'set_cookies.php'); + $this->ageCookies(3600); + $this->restart(time() + 100); + $this->assertNoCookie('session_cookie'); + $this->assertNoCookie('hour_cookie'); + $this->assertCookie('day_cookie', 'C'); + } + + function testNoClockOverDriftBy100Seconds() { + $this->get($this->samples() . 'set_cookies.php'); + $this->restart(time() + 200); + $this->assertNoCookie( + 'short_cookie', + '%s -> Please check your computer clock setting if you are not using NTP'); + } + + function testNoClockUnderDriftBy100Seconds() { + $this->get($this->samples() . 'set_cookies.php'); + $this->restart(time() + 0); + $this->assertCookie( + 'short_cookie', + 'B', + '%s -> Please check your computer clock setting if you are not using NTP'); + } + + function testCookiePath() { + $this->get($this->samples() . 'set_cookies.php'); + $this->assertNoCookie('path_cookie', 'D'); + $this->get('./path/show_cookies.php'); + $this->assertPattern('/path_cookie/'); + $this->assertCookie('path_cookie', 'D'); + } +} + +class LiveTestOfForms extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testSimpleSubmit() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('go=[Go!]'); + } + + function testDefaultFormValues() { + $this->get($this->samples() . 'form.html'); + $this->assertFieldByName('a', ''); + $this->assertFieldByName('b', 'Default text'); + $this->assertFieldByName('c', ''); + $this->assertFieldByName('d', 'd1'); + $this->assertFieldByName('e', false); + $this->assertFieldByName('f', 'on'); + $this->assertFieldByName('g', 'g3'); + $this->assertFieldByName('h', 2); + $this->assertFieldByName('go', 'Go!'); + $this->assertClickable('Go!'); + $this->assertSubmit('Go!'); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('go=[Go!]'); + $this->assertText('a=[]'); + $this->assertText('b=[Default text]'); + $this->assertText('c=[]'); + $this->assertText('d=[d1]'); + $this->assertNoText('e=['); + $this->assertText('f=[on]'); + $this->assertText('g=[g3]'); + } + + function testFormSubmissionByButtonLabel() { + $this->get($this->samples() . 'form.html'); + $this->setFieldByName('a', 'aaa'); + $this->setFieldByName('b', 'bbb'); + $this->setFieldByName('c', 'ccc'); + $this->setFieldByName('d', 'D2'); + $this->setFieldByName('e', 'on'); + $this->setFieldByName('f', false); + $this->setFieldByName('g', 'g2'); + $this->setFieldByName('h', 1); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[aaa]'); + $this->assertText('b=[bbb]'); + $this->assertText('c=[ccc]'); + $this->assertText('d=[d2]'); + $this->assertText('e=[on]'); + $this->assertNoText('f=['); + $this->assertText('g=[g2]'); + } + + function testAdditionalFormValues() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmit('Go!', array('add' => 'A'))); + $this->assertText('go=[Go!]'); + $this->assertText('add=[A]'); + } + + function testFormSubmissionByName() { + $this->get($this->samples() . 'form.html'); + $this->setFieldByName('a', 'A'); + $this->assertTrue($this->clickSubmitByName('go')); + $this->assertText('a=[A]'); + } + + function testFormSubmissionByNameAndAdditionalParameters() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmitByName('go', array('add' => 'A'))); + $this->assertText('go=[Go!]'); + $this->assertText('add=[A]'); + } + + function testFormSubmissionBySubmitButtonLabeledSubmit() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmitByName('test')); + $this->assertText('test=[Submit]'); + } + + function testFormSubmissionWithIds() { + $this->get($this->samples() . 'form.html'); + $this->assertFieldById(1, ''); + $this->assertFieldById(2, 'Default text'); + $this->assertFieldById(3, ''); + $this->assertFieldById(4, 'd1'); + $this->assertFieldById(5, false); + $this->assertFieldById(6, 'on'); + $this->assertFieldById(8, 'g3'); + $this->assertFieldById(11, 2); + $this->setFieldById(1, 'aaa'); + $this->setFieldById(2, 'bbb'); + $this->setFieldById(3, 'ccc'); + $this->setFieldById(4, 'D2'); + $this->setFieldById(5, 'on'); + $this->setFieldById(6, false); + $this->setFieldById(8, 'g2'); + $this->setFieldById(11, 'H1'); + $this->assertTrue($this->clickSubmitById(99)); + $this->assertText('a=[aaa]'); + $this->assertText('b=[bbb]'); + $this->assertText('c=[ccc]'); + $this->assertText('d=[d2]'); + $this->assertText('e=[on]'); + $this->assertNoText('f=['); + $this->assertText('g=[g2]'); + $this->assertText('h=[1]'); + $this->assertText('go=[Go!]'); + } + + function testFormSubmissionWithIdsAndAdditionnalData() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmitById(99, array('additionnal' => "data"))); + $this->assertText('additionnal=[data]'); + } + + function testFormSubmissionWithLabels() { + $this->get($this->samples() . 'form.html'); + $this->assertField('Text A', ''); + $this->assertField('Text B', 'Default text'); + $this->assertField('Text area C', ''); + $this->assertField('Selection D', 'd1'); + $this->assertField('Checkbox E', false); + $this->assertField('Checkbox F', 'on'); + $this->assertField('3', 'g3'); + $this->assertField('Selection H', 2); + $this->setField('Text A', 'aaa'); + $this->setField('Text B', 'bbb'); + $this->setField('Text area C', 'ccc'); + $this->setField('Selection D', 'D2'); + $this->setField('Checkbox E', 'on'); + $this->setField('Checkbox F', false); + $this->setField('2', 'g2'); + $this->setField('Selection H', 'H1'); + $this->clickSubmit('Go!'); + $this->assertText('a=[aaa]'); + $this->assertText('b=[bbb]'); + $this->assertText('c=[ccc]'); + $this->assertText('d=[d2]'); + $this->assertText('e=[on]'); + $this->assertNoText('f=['); + $this->assertText('g=[g2]'); + $this->assertText('h=[1]'); + $this->assertText('go=[Go!]'); + } + + function testSettingCheckboxWithBooleanTrueSetsUnderlyingValue() { + $this->get($this->samples() . 'form.html'); + $this->setField('Checkbox E', true); + $this->assertField('Checkbox E', 'on'); + $this->clickSubmit('Go!'); + $this->assertText('e=[on]'); + } + + function testFormSubmissionWithMixedPostAndGet() { + $this->get($this->samples() . 'form_with_mixed_post_and_get.html'); + $this->setField('Text A', 'Hello'); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[Hello]'); + $this->assertText('x=[X]'); + $this->assertText('y=[Y]'); + } + + function testFormSubmissionWithMixedPostAndEncodedGet() { + $this->get($this->samples() . 'form_with_mixed_post_and_get.html'); + $this->setField('Text B', 'Hello'); + $this->assertTrue($this->clickSubmit('Go encoded!')); + $this->assertText('b=[Hello]'); + $this->assertText('x=[X]'); + $this->assertText('y=[Y]'); + } + + function testFormSubmissionWithoutAction() { + $this->get($this->samples() . 'form_without_action.php?test=test'); + $this->assertText('_GET : [test]'); + $this->assertTrue($this->clickSubmit('Submit Post With Empty Action')); + $this->assertText('_GET : [test]'); + $this->assertText('_POST : [test]'); + } + + function testImageSubmissionByLabel() { + $this->get($this->samples() . 'form.html'); + $this->assertImage('Image go!'); + $this->assertTrue($this->clickImage('Image go!', 10, 12)); + $this->assertText('go_x=[10]'); + $this->assertText('go_y=[12]'); + } + + function testImageSubmissionByLabelWithAdditionalParameters() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickImage('Image go!', 10, 12, array('add' => 'A'))); + $this->assertText('add=[A]'); + } + + function testImageSubmissionByName() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickImageByName('go', 10, 12)); + $this->assertText('go_x=[10]'); + $this->assertText('go_y=[12]'); + } + + function testImageSubmissionById() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickImageById(97, 10, 12)); + $this->assertText('go_x=[10]'); + $this->assertText('go_y=[12]'); + } + + function testButtonSubmissionByLabel() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->clickSubmit('Button go!', 10, 12)); + $this->assertPattern('/go=\[ButtonGo\]/s'); + } + + function testNamelessSubmitSendsNoValue() { + $this->get($this->samples() . 'form_with_unnamed_submit.html'); + $this->click('Go!'); + $this->assertNoText('Go!'); + $this->assertNoText('submit'); + } + + function testNamelessImageSendsXAndYValues() { + $this->get($this->samples() . 'form_with_unnamed_submit.html'); + $this->clickImage('Image go!', 4, 5); + $this->assertNoText('ImageGo'); + $this->assertText('x=[4]'); + $this->assertText('y=[5]'); + } + + function testNamelessButtonSendsNoValue() { + $this->get($this->samples() . 'form_with_unnamed_submit.html'); + $this->click('Button Go!'); + $this->assertNoText('ButtonGo'); + } + + function testSelfSubmit() { + $this->get($this->samples() . 'self_form.php'); + $this->assertNoText('[Submitted]'); + $this->assertNoText('[Wrong form]'); + $this->assertTrue($this->clickSubmit()); + $this->assertText('[Submitted]'); + $this->assertNoText('[Wrong form]'); + $this->assertTitle('Test of form self submission'); + } + + function testSelfSubmitWithParameters() { + $this->get($this->samples() . 'self_form.php'); + $this->setFieldByName('visible', 'Resent'); + $this->assertTrue($this->clickSubmit()); + $this->assertText('[Resent]'); + } + + function testSettingOfBlankOption() { + $this->get($this->samples() . 'form.html'); + $this->assertTrue($this->setFieldByName('d', '')); + $this->clickSubmit('Go!'); + $this->assertText('d=[]'); + } + + function testAssertingFieldValueWithPattern() { + $this->get($this->samples() . 'form.html'); + $this->setField('c', 'A very long string'); + $this->assertField('c', new PatternExpectation('/very long/')); + } + + function testSendingMultipartFormDataEncodedForm() { + $this->get($this->samples() . 'form_data_encoded_form.html'); + $this->assertField('Text A', ''); + $this->assertField('Text B', 'Default text'); + $this->assertField('Text area C', ''); + $this->assertField('Selection D', 'd1'); + $this->assertField('Checkbox E', false); + $this->assertField('Checkbox F', 'on'); + $this->assertField('3', 'g3'); + $this->assertField('Selection H', 2); + $this->setField('Text A', 'aaa'); + $this->setField('Text B', 'bbb'); + $this->setField('Text area C', 'ccc'); + $this->setField('Selection D', 'D2'); + $this->setField('Checkbox E', 'on'); + $this->setField('Checkbox F', false); + $this->setField('2', 'g2'); + $this->setField('Selection H', 'H1'); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[aaa]'); + $this->assertText('b=[bbb]'); + $this->assertText('c=[ccc]'); + $this->assertText('d=[d2]'); + $this->assertText('e=[on]'); + $this->assertNoText('f=['); + $this->assertText('g=[g2]'); + $this->assertText('h=[1]'); + $this->assertText('go=[Go!]'); + } + + function testSettingVariousBlanksInFields() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->assertField('Text A', ''); + $this->setField('Text A', '0'); + $this->assertField('Text A', '0'); + $this->assertField('Text area B', ''); + $this->setField('Text area B', '0'); + $this->assertField('Text area B', '0'); + $this->assertField('Selection D', ''); + $this->setField('Selection D', 'D2'); + $this->assertField('Selection D', 'D2'); + $this->setField('Selection D', 'D3'); + $this->assertField('Selection D', '0'); + $this->setField('Selection D', 'D4'); + $this->assertField('Selection D', '?'); + $this->assertField('Checkbox E', ''); + $this->assertField('Checkbox F', 'on'); + $this->assertField('Checkbox G', '0'); + $this->assertField('Checkbox H', '?'); + $this->assertFieldByName('i', 'on'); + $this->setFieldByName('i', ''); + $this->assertFieldByName('i', ''); + $this->setFieldByName('i', '0'); + $this->assertFieldByName('i', '0'); + $this->setFieldByName('i', '?'); + $this->assertFieldByName('i', '?'); + } + + function testDefaultValueOfTextareaHasNewlinesAndWhitespacePreserved() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->assertField('Text area C', ' '); + } + + function chars($t) { + for ($i = 0; $i < strlen($t); $i++) { + print "[$t[$i]]"; + } + } + + function testSubmissionOfBlankFields() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->setField('Text A', ''); + $this->setField('Text area B', ''); + $this->setFieldByName('i', ''); + $this->click('Go!'); + $this->assertText('a=[]'); + $this->assertText('b=[]'); + $this->assertText('d=[]'); + $this->assertText('e=[]'); + $this->assertText('i=[]'); + } + + function testDefaultValueOfTextareaHasNewlinesAndWhitespacePreservedOnSubmission() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->click('Go!'); + $this->assertPattern('/c=\[ \]/'); + } + + function testSubmissionOfEmptyValues() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->setField('Selection D', 'D2'); + $this->click('Go!'); + $this->assertText('a=[]'); + $this->assertText('b=[]'); + $this->assertText('d=[D2]'); + $this->assertText('f=[on]'); + $this->assertText('i=[on]'); + } + + function testSubmissionOfZeroes() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->setField('Text A', '0'); + $this->setField('Text area B', '0'); + $this->setField('Selection D', 'D3'); + $this->setFieldByName('i', '0'); + $this->click('Go!'); + $this->assertText('a=[0]'); + $this->assertText('b=[0]'); + $this->assertText('d=[0]'); + $this->assertText('g=[0]'); + $this->assertText('i=[0]'); + } + + function testSubmissionOfQuestionMarks() { + $this->get($this->samples() . 'form_with_false_defaults.html'); + $this->setField('Text A', '?'); + $this->setField('Text area B', '?'); + $this->setField('Selection D', 'D4'); + $this->setFieldByName('i', '?'); + $this->click('Go!'); + $this->assertText('a=[?]'); + $this->assertText('b=[?]'); + $this->assertText('d=[?]'); + $this->assertText('h=[?]'); + $this->assertText('i=[?]'); + } + + function testSubmissionOfHtmlEncodedValues() { + $this->get($this->samples() . 'form_with_tricky_defaults.html'); + $this->assertField('Text A', '&\'"<>'); + $this->assertField('Text B', '"'); + $this->assertField('Text area C', '&\'"<>'); + $this->assertField('Selection D', "'"); + $this->assertField('Checkbox E', '&\'"<>'); + $this->assertField('Checkbox F', false); + $this->assertFieldByname('i', "'"); + $this->click('Go!'); + $this->assertText('a=[&\'"<>, "]'); + $this->assertText('c=[&\'"<>]'); + $this->assertText("d=[']"); + $this->assertText('e=[&\'"<>]'); + $this->assertText("i=[']"); + } + + function testFormActionRespectsBaseTag() { + $this->get($this->samples() . 'base_tag/form.html'); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('go=[Go!]'); + $this->assertText('a=[]'); + } +} + +class TestOfLiveMultiValueWidgets extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testDefaultFormValueSubmission() { + $this->get($this->samples() . 'multiple_widget_form.html'); + $this->assertFieldByName('a', array('a2', 'a3')); + $this->assertFieldByName('b', array('b2', 'b3')); + $this->assertFieldByName('c[]', array('c2', 'c3')); + $this->assertFieldByName('d', array('2', '3')); + $this->assertFieldByName('e', array('2', '3')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[a2, a3]'); + $this->assertText('b=[b2, b3]'); + $this->assertText('c=[c2, c3]'); + $this->assertText('d=[2, 3]'); + $this->assertText('e=[2, 3]'); + } + + function testSubmittingMultipleValues() { + $this->get($this->samples() . 'multiple_widget_form.html'); + $this->setFieldByName('a', array('a1', 'a4')); + $this->assertFieldByName('a', array('a1', 'a4')); + $this->assertFieldByName('a', array('a4', 'a1')); + $this->setFieldByName('b', array('b1', 'b4')); + $this->assertFieldByName('b', array('b1', 'b4')); + $this->setFieldByName('c[]', array('c1', 'c4')); + $this->assertField('c[]', array('c1', 'c4')); + $this->setFieldByName('d', array('1', '4')); + $this->assertField('d', array('1', '4')); + $this->setFieldByName('e', array('e1', 'e4')); + $this->assertField('e', array('1', '4')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[a1, a4]'); + $this->assertText('b=[b1, b4]'); + $this->assertText('c=[c1, c4]'); + $this->assertText('d=[1, 4]'); + $this->assertText('e=[1, 4]'); + } + + function testSettingByOptionValue() { + $this->get($this->samples() . 'multiple_widget_form.html'); + $this->setFieldByName('d', array('1', '4')); + $this->assertField('d', array('1', '4')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('d=[1, 4]'); + } + + function testSubmittingMultipleValuesByLabel() { + $this->get($this->samples() . 'multiple_widget_form.html'); + $this->setField('Multiple selection A', array('a1', 'a4')); + $this->assertField('Multiple selection A', array('a1', 'a4')); + $this->assertField('Multiple selection A', array('a4', 'a1')); + $this->setField('multiple selection C', array('c1', 'c4')); + $this->assertField('multiple selection C', array('c1', 'c4')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[a1, a4]'); + $this->assertText('c=[c1, c4]'); + } + + function testSavantStyleHiddenFieldDefaults() { + $this->get($this->samples() . 'savant_style_form.html'); + $this->assertFieldByName('a', array('a0')); + $this->assertFieldByName('b', array('b0')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[a0]'); + $this->assertText('b=[b0]'); + } + + function testSavantStyleHiddenDefaultsAreOverridden() { + $this->get($this->samples() . 'savant_style_form.html'); + $this->assertTrue($this->setFieldByName('a', array('a1'))); + $this->assertTrue($this->setFieldByName('b', 'b1')); + $this->assertTrue($this->clickSubmit('Go!')); + $this->assertText('a=[a1]'); + $this->assertText('b=[b1]'); + } + + function testSavantStyleFormSettingById() { + $this->get($this->samples() . 'savant_style_form.html'); + $this->assertFieldById(1, array('a0')); + $this->assertFieldById(4, array('b0')); + $this->assertTrue($this->setFieldById(2, 'a1')); + $this->assertTrue($this->setFieldById(5, 'b1')); + $this->assertTrue($this->clickSubmitById(99)); + $this->assertText('a=[a1]'); + $this->assertText('b=[b1]'); + } +} + +class TestOfFileUploads extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testSingleFileUpload() { + $this->get($this->samples() . 'upload_form.html'); + $this->assertTrue($this->setField('Content:', + dirname(__FILE__) . '/support/upload_sample.txt')); + $this->assertField('Content:', dirname(__FILE__) . '/support/upload_sample.txt'); + $this->click('Go!'); + $this->assertText('Sample for testing file upload'); + } + + function testMultipleFileUpload() { + $this->get($this->samples() . 'upload_form.html'); + $this->assertTrue($this->setField('Content:', + dirname(__FILE__) . '/support/upload_sample.txt')); + $this->assertTrue($this->setField('Supplemental:', + dirname(__FILE__) . '/support/supplementary_upload_sample.txt')); + $this->assertField('Supplemental:', + dirname(__FILE__) . '/support/supplementary_upload_sample.txt'); + $this->click('Go!'); + $this->assertText('Sample for testing file upload'); + $this->assertText('Some more text content'); + } + + function testBinaryFileUpload() { + $this->get($this->samples() . 'upload_form.html'); + $this->assertTrue($this->setField('Content:', + dirname(__FILE__) . '/support/latin1_sample')); + $this->click('Go!'); + $this->assertText( + implode('', file(dirname(__FILE__) . '/support/latin1_sample'))); + } +} + +class TestOfLiveHistoryNavigation extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testRetry() { + $this->get($this->samples() . 'cookie_based_counter.php'); + $this->assertPattern('/count: 1/i'); + $this->retry(); + $this->assertPattern('/count: 2/i'); + $this->retry(); + $this->assertPattern('/count: 3/i'); + } + + function testOfBackButton() { + $this->get($this->samples() . '1.html'); + $this->clickLink('2'); + $this->assertTitle('2'); + $this->assertTrue($this->back()); + $this->assertTitle('1'); + $this->assertTrue($this->forward()); + $this->assertTitle('2'); + $this->assertFalse($this->forward()); + } + + function testGetRetryResubmitsData() { + $this->assertTrue($this->get( + $this->samples() . 'network_confirm.php?a=aaa')); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[aaa]'); + $this->retry(); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[aaa]'); + } + + function testGetRetryResubmitsExtraData() { + $this->assertTrue($this->get( + $this->samples() . 'network_confirm.php', + array('a' => 'aaa'))); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[aaa]'); + $this->retry(); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[aaa]'); + } + + function testPostRetryResubmitsData() { + $this->assertTrue($this->post( + $this->samples() . 'network_confirm.php', + array('a' => 'aaa'))); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aaa]'); + $this->retry(); + $this->assertPattern('/Request method.*?
    POST<\/dd>/'); + $this->assertText('a=[aaa]'); + } + + function testGetRetryResubmitsRepeatedData() { + $this->assertTrue($this->get( + $this->samples() . 'network_confirm.php?a=1&a=2')); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[1, 2]'); + $this->retry(); + $this->assertPattern('/Request method.*?
    GET<\/dd>/'); + $this->assertText('a=[1, 2]'); + } +} + +class TestOfLiveAuthentication extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testChallengeFromProtectedPage() { + $this->get($this->samples() . 'protected/'); + $this->assertResponse(401); + $this->assertAuthentication('Basic'); + $this->assertRealm('SimpleTest basic authentication'); + $this->assertRealm(new PatternExpectation('/simpletest/i')); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->retry(); + $this->assertResponse(200); + } + + function testTrailingSlashImpliedWithinRealm() { + $this->get($this->samples() . 'protected/'); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->get($this->samples() . 'protected'); + $this->assertResponse(200); + } + + function testTrailingSlashImpliedSettingRealm() { + $this->get($this->samples() . 'protected'); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->get($this->samples() . 'protected/'); + $this->assertResponse(200); + } + + function testEncodedAuthenticationFetchesPage() { + $this->get('http://test:secret@www.lastcraft.com/test/protected/'); + $this->assertResponse(200); + } + + function testEncodedAuthenticationFetchesPageAfterTrailingSlashRedirect() { + $this->get('http://test:secret@www.lastcraft.com/test/protected'); + $this->assertResponse(200); + } + + function testRealmExtendsToWholeDirectory() { + $this->get($this->samples() . 'protected/1.html'); + $this->authenticate('test', 'secret'); + $this->clickLink('2'); + $this->assertResponse(200); + $this->clickLink('3'); + $this->assertResponse(200); + } + + function testRedirectKeepsAuthentication() { + $this->get($this->samples() . 'protected/local_redirect.php'); + $this->authenticate('test', 'secret'); + $this->assertTitle('Simple test target file'); + } + + function testRedirectKeepsEncodedAuthentication() { + $this->get('http://test:secret@www.lastcraft.com/test/protected/local_redirect.php'); + $this->assertResponse(200); + $this->assertTitle('Simple test target file'); + } + + function testSessionRestartLosesAuthentication() { + $this->get($this->samples() . 'protected/'); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->restart(); + $this->get($this->samples() . 'protected/'); + $this->assertResponse(401); + } +} + +class TestOfLoadingFrames extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testNoFramesContentWhenFramesDisabled() { + $this->ignoreFrames(); + $this->get($this->samples() . 'one_page_frameset.html'); + $this->assertTitle('Frameset for testing of SimpleTest'); + $this->assertText('This content is for no frames only'); + } + + function testPatternMatchCanReadTheOnlyFrame() { + $this->get($this->samples() . 'one_page_frameset.html'); + $this->assertText('A target for the SimpleTest test suite'); + $this->assertNoText('This content is for no frames only'); + } + + function testMessyFramesetResponsesByName() { + $this->assertTrue($this->get( + $this->samples() . 'messy_frameset.html')); + $this->assertTitle('Frameset for testing of SimpleTest'); + + $this->assertTrue($this->setFrameFocus('Front controller')); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + + $this->assertTrue($this->setFrameFocus('One')); + $this->assertResponse(200); + $this->assertLink('2'); + + $this->assertTrue($this->setFrameFocus('Frame links')); + $this->assertResponse(200); + $this->assertLink('Set one to 2'); + + $this->assertTrue($this->setFrameFocus('Counter')); + $this->assertResponse(200); + $this->assertText('Count: 1'); + + $this->assertTrue($this->setFrameFocus('Redirected')); + $this->assertResponse(200); + $this->assertText('r=rrr'); + + $this->assertTrue($this->setFrameFocus('Protected')); + $this->assertResponse(401); + + $this->assertTrue($this->setFrameFocus('Protected redirect')); + $this->assertResponse(401); + + $this->assertTrue($this->setFrameFocusByIndex(1)); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + + $this->assertTrue($this->setFrameFocusByIndex(2)); + $this->assertResponse(200); + $this->assertLink('2'); + + $this->assertTrue($this->setFrameFocusByIndex(3)); + $this->assertResponse(200); + $this->assertLink('Set one to 2'); + + $this->assertTrue($this->setFrameFocusByIndex(4)); + $this->assertResponse(200); + $this->assertText('Count: 1'); + + $this->assertTrue($this->setFrameFocusByIndex(5)); + $this->assertResponse(200); + $this->assertText('r=rrr'); + + $this->assertTrue($this->setFrameFocusByIndex(6)); + $this->assertResponse(401); + + $this->assertTrue($this->setFrameFocusByIndex(7)); + } + + function testReloadingFramesetPage() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->assertText('Count: 1'); + $this->retry(); + $this->assertText('Count: 2'); + $this->retry(); + $this->assertText('Count: 3'); + } + + function testReloadingSingleFrameWithCookieCounter() { + $this->get($this->samples() . 'counting_frameset.html'); + $this->setFrameFocus('a'); + $this->assertText('Count: 1'); + $this->setFrameFocus('b'); + $this->assertText('Count: 2'); + + $this->setFrameFocus('a'); + $this->retry(); + $this->assertText('Count: 3'); + $this->retry(); + $this->assertText('Count: 4'); + $this->setFrameFocus('b'); + $this->assertText('Count: 2'); + } + + function testReloadingFrameWhenUnfocusedReloadsWholeFrameset() { + $this->get($this->samples() . 'counting_frameset.html'); + $this->setFrameFocus('a'); + $this->assertText('Count: 1'); + $this->setFrameFocus('b'); + $this->assertText('Count: 2'); + + $this->clearFrameFocus('a'); + $this->retry(); + + $this->assertTitle('Frameset for testing of SimpleTest'); + $this->setFrameFocus('a'); + $this->assertText('Count: 3'); + $this->setFrameFocus('b'); + $this->assertText('Count: 4'); + } + + function testClickingNormalLinkReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('2'); + $this->assertLink('3'); + $this->assertText('Simple test front controller'); + } + + function testJumpToNamedPageReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->assertPattern('/Simple test front controller/'); + $this->clickLink('Index'); + $this->assertResponse(200); + $this->assertText('[action=index]'); + $this->assertText('Count: 1'); + } + + function testJumpToUnnamedPageReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('No page'); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + $this->assertText('[action=no_page]'); + $this->assertText('Count: 1'); + } + + function testJumpToUnnamedPageWithBareParameterReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('Bare action'); + $this->assertResponse(200); + $this->assertText('Simple test front controller'); + $this->assertText('[action=]'); + $this->assertText('Count: 1'); + } + + function testJumpToUnnamedPageWithEmptyQueryReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('Empty query'); + $this->assertResponse(200); + $this->assertPattern('/Simple test front controller/'); + $this->assertPattern('/raw get data.*?\[\].*?get data/si'); + $this->assertPattern('/Count: 1/'); + } + + function testJumpToUnnamedPageWithEmptyLinkReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('Empty link'); + $this->assertResponse(200); + $this->assertPattern('/Simple test front controller/'); + $this->assertPattern('/raw get data.*?\[\].*?get data/si'); + $this->assertPattern('/Count: 1/'); + } + + function testJumpBackADirectoryLevelReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('Down one'); + $this->assertPattern('/index of .*\/test/i'); + $this->assertPattern('/Count: 1/'); + } + + function testSubmitToNamedPageReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->assertPattern('/Simple test front controller/'); + $this->clickSubmit('Index'); + $this->assertResponse(200); + $this->assertText('[action=Index]'); + $this->assertText('Count: 1'); + } + + function testSubmitToSameDirectoryReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickSubmit('Same directory'); + $this->assertResponse(200); + $this->assertText('[action=Same+directory]'); + $this->assertText('Count: 1'); + } + + function testSubmitToEmptyActionReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickSubmit('Empty action'); + $this->assertResponse(200); + $this->assertText('[action=Empty+action]'); + $this->assertText('Count: 1'); + } + + function testSubmitToNoActionReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickSubmit('No action'); + $this->assertResponse(200); + $this->assertText('[action=No+action]'); + $this->assertText('Count: 1'); + } + + function testSubmitBackADirectoryLevelReplacesJustThatFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickSubmit('Down one'); + $this->assertPattern('/index of .*\/test/i'); + $this->assertPattern('/Count: 1/'); + } + + function testTopLinkExitsFrameset() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->clickLink('Exit the frameset'); + $this->assertTitle('Simple test target file'); + } + + function testLinkInOnePageCanLoadAnother() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->assertNoLink('3'); + $this->clickLink('Set one to 2'); + $this->assertLink('3'); + $this->assertNoLink('2'); + $this->assertTitle('Frameset for testing of SimpleTest'); + } + + function testFrameWithRelativeLinksRespectsBaseTagForThatPage() { + $this->get($this->samples() . 'base_tag/frameset.html'); + $this->click('Back to test pages'); + $this->assertTitle('Frameset for testing of SimpleTest'); + $this->assertText('A target for the SimpleTest test suite'); + } + + function testRelativeLinkInFrameIsNotAffectedByFramesetBaseTag() { + $this->get($this->samples() . 'base_tag/frameset_with_base_tag.html'); + $this->assertText('This is page 1'); + $this->click('To page 2'); + $this->assertTitle('Frameset for testing of SimpleTest'); + $this->assertText('This is page 2'); + } +} + +class TestOfFrameAuthentication extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testUnauthenticatedFrameSendsChallenge() { + $this->get($this->samples() . 'protected/'); + $this->setFrameFocus('Protected'); + $this->assertAuthentication('Basic'); + $this->assertRealm('SimpleTest basic authentication'); + $this->assertResponse(401); + } + + function testCanReadFrameFromAlreadyAuthenticatedRealm() { + $this->get($this->samples() . 'protected/'); + $this->authenticate('test', 'secret'); + $this->get($this->samples() . 'messy_frameset.html'); + $this->setFrameFocus('Protected'); + $this->assertResponse(200); + $this->assertText('A target for the SimpleTest test suite'); + } + + function testCanAuthenticateFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->setFrameFocus('Protected'); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->assertText('A target for the SimpleTest test suite'); + $this->clearFrameFocus(); + $this->assertText('Count: 1'); + } + + function testCanAuthenticateRedirectedFrame() { + $this->get($this->samples() . 'messy_frameset.html'); + $this->setFrameFocus('Protected redirect'); + $this->assertResponse(401); + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->assertText('A target for the SimpleTest test suite'); + $this->clearFrameFocus(); + $this->assertText('Count: 1'); + } +} + +class TestOfNestedFrames extends SimpleTestAcceptanceTest { + function setUp() { + $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion()); + } + + function testCanNavigateToSpecificContent() { + $this->get($this->samples() . 'nested_frameset.html'); + $this->assertTitle('Nested frameset for testing of SimpleTest'); + + $this->assertPattern('/This is frame A/'); + $this->assertPattern('/This is frame B/'); + $this->assertPattern('/Simple test front controller/'); + $this->assertLink('2'); + $this->assertLink('Set one to 2'); + $this->assertPattern('/Count: 1/'); + $this->assertPattern('/r=rrr/'); + + $this->setFrameFocus('pair'); + $this->assertPattern('/This is frame A/'); + $this->assertPattern('/This is frame B/'); + $this->assertNoPattern('/Simple test front controller/'); + $this->assertNoLink('2'); + + $this->setFrameFocus('aaa'); + $this->assertPattern('/This is frame A/'); + $this->assertNoPattern('/This is frame B/'); + + $this->clearFrameFocus(); + $this->assertResponse(200); + $this->setFrameFocus('messy'); + $this->assertResponse(200); + $this->setFrameFocus('Front controller'); + $this->assertResponse(200); + $this->assertPattern('/Simple test front controller/'); + $this->assertNoLink('2'); + } + + function testReloadingFramesetPage() { + $this->get($this->samples() . 'nested_frameset.html'); + $this->assertPattern('/Count: 1/'); + $this->retry(); + $this->assertPattern('/Count: 2/'); + $this->retry(); + $this->assertPattern('/Count: 3/'); + } + + function testRetryingNestedPageOnlyRetriesThatSet() { + $this->get($this->samples() . 'nested_frameset.html'); + $this->assertPattern('/Count: 1/'); + $this->setFrameFocus('messy'); + $this->retry(); + $this->assertPattern('/Count: 2/'); + $this->setFrameFocus('Counter'); + $this->retry(); + $this->assertPattern('/Count: 3/'); + + $this->clearFrameFocus(); + $this->setFrameFocus('messy'); + $this->setFrameFocus('Front controller'); + $this->retry(); + + $this->clearFrameFocus(); + $this->assertPattern('/Count: 3/'); + } + + function testAuthenticatingNestedPage() { + $this->get($this->samples() . 'nested_frameset.html'); + $this->setFrameFocus('messy'); + $this->setFrameFocus('Protected'); + $this->assertAuthentication('Basic'); + $this->assertRealm('SimpleTest basic authentication'); + $this->assertResponse(401); + + $this->authenticate('test', 'secret'); + $this->assertResponse(200); + $this->assertPattern('/A target for the SimpleTest test suite/'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/adapter_test.php b/application/libraries/simpletest/test/adapter_test.php new file mode 100644 index 00000000000..c1a06a2f653 --- /dev/null +++ b/application/libraries/simpletest/test/adapter_test.php @@ -0,0 +1,50 @@ +assertTrue(true, "PEAR true"); + $this->assertFalse(false, "PEAR false"); + } + + function testName() { + $this->assertTrue($this->getName() == get_class($this)); + } + + function testPass() { + $this->pass("PEAR pass"); + } + + function testNulls() { + $value = null; + $this->assertNull($value, "PEAR null"); + $value = 0; + $this->assertNotNull($value, "PEAR not null"); + } + + function testType() { + $this->assertType("Hello", "string", "PEAR type"); + } + + function testEquals() { + $this->assertEquals(12, 12, "PEAR identity"); + $this->setLooselyTyped(true); + $this->assertEquals("12", 12, "PEAR equality"); + } + + function testSame() { + $same = new SameTestClass(); + $this->assertSame($same, $same, "PEAR same"); + } + + function testRegExp() { + $this->assertRegExp('/hello/', "A big hello from me", "PEAR regex"); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/all_tests.php b/application/libraries/simpletest/test/all_tests.php new file mode 100644 index 00000000000..99ce9451e32 --- /dev/null +++ b/application/libraries/simpletest/test/all_tests.php @@ -0,0 +1,13 @@ +TestSuite('All tests for SimpleTest ' . SimpleTest::getVersion()); + $this->addFile(dirname(__FILE__) . '/unit_tests.php'); + $this->addFile(dirname(__FILE__) . '/shell_test.php'); + $this->addFile(dirname(__FILE__) . '/live_test.php'); + $this->addFile(dirname(__FILE__) . '/acceptance_test.php'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/authentication_test.php b/application/libraries/simpletest/test/authentication_test.php new file mode 100644 index 00000000000..081cccddfae --- /dev/null +++ b/application/libraries/simpletest/test/authentication_test.php @@ -0,0 +1,145 @@ +assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/hello.html'))); + } + + function testInsideWithLongerUrl() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/hello.html'))); + } + + function testBelowRootIsOutside() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/more/hello.html'))); + } + + function testOldNetscapeDefinitionIsOutside() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/')); + $this->assertFalse($realm->isWithin( + new SimpleUrl('http://www.here.com/pathmore/hello.html'))); + } + + function testInsideWithMissingTrailingSlash() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path'))); + } + + function testDifferentPageNameStillInside() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/hello.html')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/goodbye.html'))); + } + + function testNewUrlInSameDirectoryDoesNotChangeRealm() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/hello.html')); + $realm->stretch(new SimpleUrl('http://www.here.com/path/goodbye.html')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/index.html'))); + $this->assertFalse($realm->isWithin( + new SimpleUrl('http://www.here.com/index.html'))); + } + + function testNewUrlMakesRealmTheCommonPath() { + $realm = new SimpleRealm( + 'Basic', + new SimpleUrl('http://www.here.com/path/here/hello.html')); + $realm->stretch(new SimpleUrl('http://www.here.com/path/there/goodbye.html')); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/here/index.html'))); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/there/index.html'))); + $this->assertTrue($realm->isWithin( + new SimpleUrl('http://www.here.com/path/index.html'))); + $this->assertFalse($realm->isWithin( + new SimpleUrl('http://www.here.com/index.html'))); + $this->assertFalse($realm->isWithin( + new SimpleUrl('http://www.here.com/paths/index.html'))); + $this->assertFalse($realm->isWithin( + new SimpleUrl('http://www.here.com/pathindex.html'))); + } +} + +class TestOfAuthenticator extends UnitTestCase { + + function testNoRealms() { + $request = new MockSimpleHttpRequest(); + $request->expectNever('addHeaderLine'); + $authenticator = new SimpleAuthenticator(); + $authenticator->addHeaders($request, new SimpleUrl('http://here.com/')); + } + + function &createSingleRealm() { + $authenticator = new SimpleAuthenticator(); + $authenticator->addRealm( + new SimpleUrl('http://www.here.com/path/hello.html'), + 'Basic', + 'Sanctuary'); + $authenticator->setIdentityForRealm('www.here.com', 'Sanctuary', 'test', 'secret'); + return $authenticator; + } + + function testOutsideRealm() { + $request = new MockSimpleHttpRequest(); + $request->expectNever('addHeaderLine'); + $authenticator = &$this->createSingleRealm(); + $authenticator->addHeaders( + $request, + new SimpleUrl('http://www.here.com/hello.html')); + } + + function testWithinRealm() { + $request = new MockSimpleHttpRequest(); + $request->expectOnce('addHeaderLine'); + $authenticator = &$this->createSingleRealm(); + $authenticator->addHeaders( + $request, + new SimpleUrl('http://www.here.com/path/more/hello.html')); + } + + function testRestartingClearsRealm() { + $request = new MockSimpleHttpRequest(); + $request->expectNever('addHeaderLine'); + $authenticator = &$this->createSingleRealm(); + $authenticator->restartSession(); + $authenticator->addHeaders( + $request, + new SimpleUrl('http://www.here.com/hello.html')); + } + + function testDifferentHostIsOutsideRealm() { + $request = new MockSimpleHttpRequest(); + $request->expectNever('addHeaderLine'); + $authenticator = &$this->createSingleRealm(); + $authenticator->addHeaders( + $request, + new SimpleUrl('http://here.com/path/hello.html')); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/autorun_test.php b/application/libraries/simpletest/test/autorun_test.php new file mode 100644 index 00000000000..d85ea19897c --- /dev/null +++ b/application/libraries/simpletest/test/autorun_test.php @@ -0,0 +1,23 @@ +addFile(dirname(__FILE__) . '/support/test1.php'); + $this->assertEqual($tests->getSize(), 1); + } + + function testExitStatusOneIfTestsFail() { + exec('php ' . dirname(__FILE__) . '/support/failing_test.php', $output, $exit_status); + $this->assertEqual($exit_status, 1); + } + + function testExitStatusZeroIfTestsPass() { + exec('php ' . dirname(__FILE__) . '/support/passing_test.php', $output, $exit_status); + $this->assertEqual($exit_status, 0); + } +} + +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/bad_test_suite.php b/application/libraries/simpletest/test/bad_test_suite.php new file mode 100644 index 00000000000..b426013be40 --- /dev/null +++ b/application/libraries/simpletest/test/bad_test_suite.php @@ -0,0 +1,10 @@ +TestSuite('Two bad test cases'); + $this->addFile(dirname(__FILE__) . '/support/empty_test_file.php'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/browser_test.php b/application/libraries/simpletest/test/browser_test.php new file mode 100644 index 00000000000..3a52aaa8ff4 --- /dev/null +++ b/application/libraries/simpletest/test/browser_test.php @@ -0,0 +1,802 @@ +assertIdentical($history->getUrl(), false); + $this->assertIdentical($history->getParameters(), false); + } + + function testCannotMoveInEmptyHistory() { + $history = new SimpleBrowserHistory(); + $this->assertFalse($history->back()); + $this->assertFalse($history->forward()); + } + + function testCurrentTargetAccessors() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.here.com/'), + new SimpleGetEncoding()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.here.com/')); + $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); + } + + function testSecondEntryAccessors() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.second.com/'), + new SimplePostEncoding(array('a' => 1))); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/')); + $this->assertIdentical( + $history->getParameters(), + new SimplePostEncoding(array('a' => 1))); + } + + function testGoingBackwards() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.second.com/'), + new SimplePostEncoding(array('a' => 1))); + $this->assertTrue($history->back()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); + $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); + } + + function testGoingBackwardsOffBeginning() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $this->assertFalse($history->back()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); + $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); + } + + function testGoingForwardsOffEnd() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $this->assertFalse($history->forward()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); + $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); + } + + function testGoingBackwardsAndForwards() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.second.com/'), + new SimplePostEncoding(array('a' => 1))); + $this->assertTrue($history->back()); + $this->assertTrue($history->forward()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/')); + $this->assertIdentical( + $history->getParameters(), + new SimplePostEncoding(array('a' => 1))); + } + + function testNewEntryReplacesNextOne() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.second.com/'), + new SimplePostEncoding(array('a' => 1))); + $history->back(); + $history->recordEntry( + new SimpleUrl('http://www.third.com/'), + new SimpleGetEncoding()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.third.com/')); + $this->assertIdentical($history->getParameters(), new SimpleGetEncoding()); + } + + function testNewEntryDropsFutureEntries() { + $history = new SimpleBrowserHistory(); + $history->recordEntry( + new SimpleUrl('http://www.first.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.second.com/'), + new SimpleGetEncoding()); + $history->recordEntry( + new SimpleUrl('http://www.third.com/'), + new SimpleGetEncoding()); + $history->back(); + $history->back(); + $history->recordEntry( + new SimpleUrl('http://www.fourth.com/'), + new SimpleGetEncoding()); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.fourth.com/')); + $this->assertFalse($history->forward()); + $history->back(); + $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/')); + $this->assertFalse($history->back()); + } +} + +class TestOfParsedPageAccess extends UnitTestCase { + + function loadPage(&$page) { + $response = new MockSimpleHttpResponse($this); + $agent = new MockSimpleUserAgent($this); + $agent->returns('fetchResponse', $response); + + $browser = new MockParseSimpleBrowser($this); + $browser->returns('createUserAgent', $agent); + $browser->returns('parse', $page); + $browser->__construct(); + + $browser->get('http://this.com/page.html'); + return $browser; + } + + function testAccessorsWhenNoPage() { + $agent = new MockSimpleUserAgent($this); + $browser = new MockParseSimpleBrowser($this); + $browser->returns('createUserAgent', $agent); + $browser->__construct(); + $this->assertEqual($browser->getContent(), ''); + } + + function testParse() { + $page = new MockSimplePage(); + $page->setReturnValue('getRequest', "GET here.html\r\n\r\n"); + $page->setReturnValue('getRaw', 'Raw HTML'); + $page->setReturnValue('getTitle', 'Here'); + $page->setReturnValue('getFrameFocus', 'Frame'); + $page->setReturnValue('getMimeType', 'text/html'); + $page->setReturnValue('getResponseCode', 200); + $page->setReturnValue('getAuthentication', 'Basic'); + $page->setReturnValue('getRealm', 'Somewhere'); + $page->setReturnValue('getTransportError', 'Ouch!'); + + $browser = $this->loadPage($page); + $this->assertEqual($browser->getRequest(), "GET here.html\r\n\r\n"); + $this->assertEqual($browser->getContent(), 'Raw HTML'); + $this->assertEqual($browser->getTitle(), 'Here'); + $this->assertEqual($browser->getFrameFocus(), 'Frame'); + $this->assertIdentical($browser->getResponseCode(), 200); + $this->assertEqual($browser->getMimeType(), 'text/html'); + $this->assertEqual($browser->getAuthentication(), 'Basic'); + $this->assertEqual($browser->getRealm(), 'Somewhere'); + $this->assertEqual($browser->getTransportError(), 'Ouch!'); + } + + function testLinkAffirmationWhenPresent() { + $page = new MockSimplePage(); + $page->setReturnValue('getUrlsByLabel', array('http://www.nowhere.com')); + $page->expectOnce('getUrlsByLabel', array('a link label')); + $browser = $this->loadPage($page); + $this->assertIdentical($browser->getLink('a link label'), 'http://www.nowhere.com'); + } + + function testLinkAffirmationByIdWhenPresent() { + $page = new MockSimplePage(); + $page->setReturnValue('getUrlById', 'a_page.com', array(99)); + $page->setReturnValue('getUrlById', false, array('*')); + $browser = $this->loadPage($page); + $this->assertIdentical($browser->getLinkById(99), 'a_page.com'); + $this->assertFalse($browser->getLinkById(98)); + } + + function testSettingFieldIsPassedToPage() { + $page = new MockSimplePage(); + $page->expectOnce('setField', array(new SimpleByLabelOrName('key'), 'Value', false)); + $page->setReturnValue('getField', 'Value'); + $browser = $this->loadPage($page); + $this->assertEqual($browser->getField('key'), 'Value'); + $browser->setField('key', 'Value'); + } +} + +class TestOfBrowserNavigation extends UnitTestCase { + function createBrowser($agent, $page) { + $browser = new MockParseSimpleBrowser(); + $browser->returns('createUserAgent', $agent); + $browser->returns('parse', $page); + $browser->__construct(); + return $browser; + } + + function testBrowserRequestMethods() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt( + 0, + 'fetchResponse', + array(new SimpleUrl('http://this.com/get.req'), new SimpleGetEncoding())); + $agent->expectAt( + 1, + 'fetchResponse', + array(new SimpleUrl('http://this.com/post.req'), new SimplePostEncoding())); + $agent->expectAt( + 2, + 'fetchResponse', + array(new SimpleUrl('http://this.com/put.req'), new SimplePutEncoding())); + $agent->expectAt( + 3, + 'fetchResponse', + array(new SimpleUrl('http://this.com/delete.req'), new SimpleDeleteEncoding())); + $agent->expectAt( + 4, + 'fetchResponse', + array(new SimpleUrl('http://this.com/head.req'), new SimpleHeadEncoding())); + $agent->expectCallCount('fetchResponse', 5); + + $page = new MockSimplePage(); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/get.req'); + $browser->post('http://this.com/post.req'); + $browser->put('http://this.com/put.req'); + $browser->delete('http://this.com/delete.req'); + $browser->head('http://this.com/head.req'); + } + + function testClickLinkRequestsPage() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt( + 0, + 'fetchResponse', + array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding())); + $agent->expectAt( + 1, + 'fetchResponse', + array(new SimpleUrl('http://this.com/new.html'), new SimpleGetEncoding())); + $agent->expectCallCount('fetchResponse', 2); + + $page = new MockSimplePage(); + $page->setReturnValue('getUrlsByLabel', array(new SimpleUrl('http://this.com/new.html'))); + $page->expectOnce('getUrlsByLabel', array('New')); + $page->setReturnValue('getRaw', 'A page'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickLink('New')); + } + + function testClickLinkWithUnknownFrameStillRequestsWholePage() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt( + 0, + 'fetchResponse', + array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding())); + $target = new SimpleUrl('http://this.com/new.html'); + $target->setTarget('missing'); + $agent->expectAt( + 1, + 'fetchResponse', + array($target, new SimpleGetEncoding())); + $agent->expectCallCount('fetchResponse', 2); + + $parsed_url = new SimpleUrl('http://this.com/new.html'); + $parsed_url->setTarget('missing'); + + $page = new MockSimplePage(); + $page->setReturnValue('getUrlsByLabel', array($parsed_url)); + $page->setReturnValue('hasFrames', false); + $page->expectOnce('getUrlsByLabel', array('New')); + $page->setReturnValue('getRaw', 'A page'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickLink('New')); + } + + function testClickingMissingLinkFails() { + $agent = new MockSimpleUserAgent($this); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $page = new MockSimplePage(); + $page->setReturnValue('getUrlsByLabel', array()); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $this->assertTrue($browser->get('http://this.com/page.html')); + $this->assertFalse($browser->clickLink('New')); + } + + function testClickIndexedLink() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt( + 1, + 'fetchResponse', + array(new SimpleUrl('1.html'), new SimpleGetEncoding())); + $agent->expectCallCount('fetchResponse', 2); + + $page = new MockSimplePage(); + $page->setReturnValue( + 'getUrlsByLabel', + array(new SimpleUrl('0.html'), new SimpleUrl('1.html'))); + $page->setReturnValue('getRaw', 'A page'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickLink('New', 1)); + } + + function testClinkLinkById() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt(1, 'fetchResponse', array( + new SimpleUrl('http://this.com/link.html'), + new SimpleGetEncoding())); + $agent->expectCallCount('fetchResponse', 2); + + $page = new MockSimplePage(); + $page->setReturnValue('getUrlById', new SimpleUrl('http://this.com/link.html')); + $page->expectOnce('getUrlById', array(2)); + $page->setReturnValue('getRaw', 'A page'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickLinkById(2)); + } + + function testClickingMissingLinkIdFails() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $page = new MockSimplePage(); + $page->setReturnValue('getUrlById', false); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertFalse($browser->clickLink(0)); + } + + function testSubmitFormByLabel() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt(1, 'fetchResponse', array( + new SimpleUrl('http://this.com/handler.html'), + new SimplePostEncoding(array('a' => 'A')))); + $agent->expectCallCount('fetchResponse', 2); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); + $form->expectOnce('submitButton', array(new SimpleByLabel('Go'), false)); + + $page = new MockSimplePage(); + $page->returns('getFormBySubmit', $form); + $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Go'))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickSubmit('Go')); + } + + function testDefaultSubmitFormByLabel() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt(1, 'fetchResponse', array( + new SimpleUrl('http://this.com/page.html'), + new SimpleGetEncoding(array('a' => 'A')))); + $agent->expectCallCount('fetchResponse', 2); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/page.html')); + $form->setReturnValue('getMethod', 'get'); + $form->setReturnValue('submitButton', new SimpleGetEncoding(array('a' => 'A'))); + + $page = new MockSimplePage(); + $page->returns('getFormBySubmit', $form); + $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Submit'))); + $page->setReturnValue('getRaw', 'stuff'); + $page->setReturnValue('getUrl', new SimpleUrl('http://this.com/page.html')); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickSubmit()); + } + + function testSubmitFormByName() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); + + $page = new MockSimplePage(); + $page->returns('getFormBySubmit', $form); + $page->expectOnce('getFormBySubmit', array(new SimpleByName('me'))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickSubmitByName('me')); + } + + function testSubmitFormById() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A'))); + $form->expectOnce('submitButton', array(new SimpleById(99), false)); + + $page = new MockSimplePage(); + $page->returns('getFormBySubmit', $form); + $page->expectOnce('getFormBySubmit', array(new SimpleById(99))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickSubmitById(99)); + } + + function testSubmitFormByImageLabel() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); + $form->expectOnce('submitImage', array(new SimpleByLabel('Go!'), 10, 11, false)); + + $page = new MockSimplePage(); + $page->returns('getFormByImage', $form); + $page->expectOnce('getFormByImage', array(new SimpleByLabel('Go!'))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickImage('Go!', 10, 11)); + } + + function testSubmitFormByImageName() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); + $form->expectOnce('submitImage', array(new SimpleByName('a'), 10, 11, false)); + + $page = new MockSimplePage(); + $page->returns('getFormByImage', $form); + $page->expectOnce('getFormByImage', array(new SimpleByName('a'))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickImageByName('a', 10, 11)); + } + + function testSubmitFormByImageId() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A'))); + $form->expectOnce('submitImage', array(new SimpleById(99), 10, 11, false)); + + $page = new MockSimplePage(); + $page->returns('getFormByImage', $form); + $page->expectOnce('getFormByImage', array(new SimpleById(99))); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->clickImageById(99, 10, 11)); + } + + function testSubmitFormByFormId() { + $agent = new MockSimpleUserAgent(); + $agent->returns('fetchResponse', new MockSimpleHttpResponse()); + $agent->expectAt(1, 'fetchResponse', array( + new SimpleUrl('http://this.com/handler.html'), + new SimplePostEncoding(array('a' => 'A')))); + $agent->expectCallCount('fetchResponse', 2); + + $form = new MockSimpleForm(); + $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html')); + $form->setReturnValue('getMethod', 'post'); + $form->setReturnValue('submit', new SimplePostEncoding(array('a' => 'A'))); + + $page = new MockSimplePage(); + $page->returns('getFormById', $form); + $page->expectOnce('getFormById', array(33)); + $page->setReturnValue('getRaw', 'stuff'); + + $browser = $this->createBrowser($agent, $page); + $browser->get('http://this.com/page.html'); + $this->assertTrue($browser->submitFormById(33)); + } +} + +class TestOfBrowserFrames extends UnitTestCase { + + function createBrowser($agent) { + $browser = new MockUserAgentSimpleBrowser(); + $browser->returns('createUserAgent', $agent); + $browser->__construct(); + return $browser; + } + + function createUserAgent($pages) { + $agent = new MockSimpleUserAgent(); + foreach ($pages as $url => $raw) { + $url = new SimpleUrl($url); + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getUrl', $url); + $response->setReturnValue('getContent', $raw); + $agent->returns('fetchResponse', $response, array($url, '*')); + } + return $agent; + } + + function testSimplePageHasNoFrames() { + $browser = $this->createBrowser($this->createUserAgent( + array('http://site.with.no.frames/' => 'A non-framed page'))); + $this->assertEqual( + $browser->get('http://site.with.no.frames/'), + 'A non-framed page'); + $this->assertIdentical($browser->getFrames(), 'http://site.with.no.frames/'); + } + + function testFramesetWithSingleFrame() { + $frameset = ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.one.frame/' => $frameset, + 'http://site.with.one.frame/frame.html' => 'A frame'))); + $this->assertEqual($browser->get('http://site.with.one.frame/'), 'A frame'); + $this->assertIdentical( + $browser->getFrames(), + array('a' => 'http://site.with.one.frame/frame.html')); + } + + function testTitleTakenFromFramesetPage() { + $frameset = 'Frameset title' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.one.frame/' => $frameset, + 'http://site.with.one.frame/frame.html' => 'Page title'))); + $browser->get('http://site.with.one.frame/'); + $this->assertEqual($browser->getTitle(), 'Frameset title'); + } + + function testFramesetWithSingleUnnamedFrame() { + $frameset = ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.one.frame/' => $frameset, + 'http://site.with.one.frame/frame.html' => 'One frame'))); + $this->assertEqual( + $browser->get('http://site.with.one.frame/'), + 'One frame'); + $this->assertIdentical( + $browser->getFrames(), + array(1 => 'http://site.with.one.frame/frame.html')); + } + + function testFramesetWithMultipleFrames() { + $frameset = '' . + '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.frames/' => $frameset, + 'http://site.with.frames/frame_a.html' => 'A frame', + 'http://site.with.frames/frame_b.html' => 'B frame', + 'http://site.with.frames/frame_c.html' => 'C frame'))); + $this->assertEqual( + $browser->get('http://site.with.frames/'), + 'A frameB frameC frame'); + $this->assertIdentical($browser->getFrames(), array( + 'a' => 'http://site.with.frames/frame_a.html', + 'b' => 'http://site.with.frames/frame_b.html', + 'c' => 'http://site.with.frames/frame_c.html')); + } + + function testFrameFocusByName() { + $frameset = '' . + '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.frames/' => $frameset, + 'http://site.with.frames/frame_a.html' => 'A frame', + 'http://site.with.frames/frame_b.html' => 'B frame', + 'http://site.with.frames/frame_c.html' => 'C frame'))); + $browser->get('http://site.with.frames/'); + $browser->setFrameFocus('a'); + $this->assertEqual($browser->getContent(), 'A frame'); + $browser->setFrameFocus('b'); + $this->assertEqual($browser->getContent(), 'B frame'); + $browser->setFrameFocus('c'); + $this->assertEqual($browser->getContent(), 'C frame'); + } + + function testFramesetWithSomeNamedFrames() { + $frameset = '' . + '' . + '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.frames/' => $frameset, + 'http://site.with.frames/frame_a.html' => 'A frame', + 'http://site.with.frames/frame_b.html' => 'B frame', + 'http://site.with.frames/frame_c.html' => 'C frame', + 'http://site.with.frames/frame_d.html' => 'D frame'))); + $this->assertEqual( + $browser->get('http://site.with.frames/'), + 'A frameB frameC frameD frame'); + $this->assertIdentical($browser->getFrames(), array( + 'a' => 'http://site.with.frames/frame_a.html', + 2 => 'http://site.with.frames/frame_b.html', + 'c' => 'http://site.with.frames/frame_c.html', + 4 => 'http://site.with.frames/frame_d.html')); + } + + function testFrameFocusWithMixedNamesAndIndexes() { + $frameset = '' . + '' . + '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.frames/' => $frameset, + 'http://site.with.frames/frame_a.html' => 'A frame', + 'http://site.with.frames/frame_b.html' => 'B frame', + 'http://site.with.frames/frame_c.html' => 'C frame', + 'http://site.with.frames/frame_d.html' => 'D frame'))); + $browser->get('http://site.with.frames/'); + $browser->setFrameFocus('a'); + $this->assertEqual($browser->getContent(), 'A frame'); + $browser->setFrameFocus(2); + $this->assertEqual($browser->getContent(), 'B frame'); + $browser->setFrameFocus('c'); + $this->assertEqual($browser->getContent(), 'C frame'); + $browser->setFrameFocus(4); + $this->assertEqual($browser->getContent(), 'D frame'); + $browser->clearFrameFocus(); + $this->assertEqual($browser->getContent(), 'A frameB frameC frameD frame'); + } + + function testNestedFrameset() { + $inner = '' . + '' . + ''; + $outer = '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.nested.frame/' => $outer, + 'http://site.with.nested.frame/inner.html' => $inner, + 'http://site.with.nested.frame/page.html' => 'The page'))); + $this->assertEqual( + $browser->get('http://site.with.nested.frame/'), + 'The page'); + $this->assertIdentical($browser->getFrames(), array( + 'inner' => array( + 'page' => 'http://site.with.nested.frame/page.html'))); + } + + function testCanNavigateToNestedFrame() { + $inner = '' . + '' . + '' . + ''; + $outer = '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.nested.frames/' => $outer, + 'http://site.with.nested.frames/inner.html' => $inner, + 'http://site.with.nested.frames/one.html' => 'Page one', + 'http://site.with.nested.frames/two.html' => 'Page two', + 'http://site.with.nested.frames/three.html' => 'Page three'))); + + $browser->get('http://site.with.nested.frames/'); + $this->assertEqual($browser->getContent(), 'Page onePage twoPage three'); + + $this->assertTrue($browser->setFrameFocus('inner')); + $this->assertEqual($browser->getFrameFocus(), array('inner')); + $this->assertTrue($browser->setFrameFocus('one')); + $this->assertEqual($browser->getFrameFocus(), array('inner', 'one')); + $this->assertEqual($browser->getContent(), 'Page one'); + + $this->assertTrue($browser->setFrameFocus('two')); + $this->assertEqual($browser->getFrameFocus(), array('inner', 'two')); + $this->assertEqual($browser->getContent(), 'Page two'); + + $browser->clearFrameFocus(); + $this->assertTrue($browser->setFrameFocus('three')); + $this->assertEqual($browser->getFrameFocus(), array('three')); + $this->assertEqual($browser->getContent(), 'Page three'); + + $this->assertTrue($browser->setFrameFocus('inner')); + $this->assertEqual($browser->getContent(), 'Page onePage two'); + } + + function testCanNavigateToNestedFrameByIndex() { + $inner = '' . + '' . + '' . + ''; + $outer = '' . + '' . + '' . + ''; + $browser = $this->createBrowser($this->createUserAgent(array( + 'http://site.with.nested.frames/' => $outer, + 'http://site.with.nested.frames/inner.html' => $inner, + 'http://site.with.nested.frames/one.html' => 'Page one', + 'http://site.with.nested.frames/two.html' => 'Page two', + 'http://site.with.nested.frames/three.html' => 'Page three'))); + + $browser->get('http://site.with.nested.frames/'); + $this->assertEqual($browser->getContent(), 'Page onePage twoPage three'); + + $this->assertTrue($browser->setFrameFocusByIndex(1)); + $this->assertEqual($browser->getFrameFocus(), array(1)); + $this->assertTrue($browser->setFrameFocusByIndex(1)); + $this->assertEqual($browser->getFrameFocus(), array(1, 1)); + $this->assertEqual($browser->getContent(), 'Page one'); + + $this->assertTrue($browser->setFrameFocusByIndex(2)); + $this->assertEqual($browser->getFrameFocus(), array(1, 2)); + $this->assertEqual($browser->getContent(), 'Page two'); + + $browser->clearFrameFocus(); + $this->assertTrue($browser->setFrameFocusByIndex(2)); + $this->assertEqual($browser->getFrameFocus(), array(2)); + $this->assertEqual($browser->getContent(), 'Page three'); + + $this->assertTrue($browser->setFrameFocusByIndex(1)); + $this->assertEqual($browser->getContent(), 'Page onePage two'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/collector_test.php b/application/libraries/simpletest/test/collector_test.php new file mode 100644 index 00000000000..efdbf377ece --- /dev/null +++ b/application/libraries/simpletest/test/collector_test.php @@ -0,0 +1,50 @@ +expectMinimumCallCount('addFile', 2); + $suite->expect( + 'addFile', + array(new PatternExpectation('/collectable\\.(1|2)$/'))); + $collector = new SimpleCollector(); + $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); + } +} + +class TestOfPatternCollector extends UnitTestCase { + + function testAddingEverythingToGroup() { + $suite = new MockTestSuite(); + $suite->expectCallCount('addFile', 2); + $suite->expect( + 'addFile', + array(new PatternExpectation('/collectable\\.(1|2)$/'))); + $collector = new SimplePatternCollector('/.*/'); + $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); + } + + function testOnlyMatchedFilesAreAddedToGroup() { + $suite = new MockTestSuite(); + $suite->expectOnce('addFile', array(new PathEqualExpectation( + dirname(__FILE__) . '/support/collector/collectable.1'))); + $collector = new SimplePatternCollector('/1$/'); + $collector->collect($suite, dirname(__FILE__) . '/support/collector/'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/command_line_test.php b/application/libraries/simpletest/test/command_line_test.php new file mode 100644 index 00000000000..5baabff33c6 --- /dev/null +++ b/application/libraries/simpletest/test/command_line_test.php @@ -0,0 +1,40 @@ +assertIdentical($parser->getTest(), ''); + $this->assertIdentical($parser->getTestCase(), ''); + } + + function testNotXmlByDefault() { + $parser = new SimpleCommandLineParser(array()); + $this->assertFalse($parser->isXml()); + } + + function testCanDetectRequestForXml() { + $parser = new SimpleCommandLineParser(array('--xml')); + $this->assertTrue($parser->isXml()); + } + + function testCanReadAssignmentSyntax() { + $parser = new SimpleCommandLineParser(array('--test=myTest')); + $this->assertEqual($parser->getTest(), 'myTest'); + } + + function testCanReadFollowOnSyntax() { + $parser = new SimpleCommandLineParser(array('--test', 'myTest')); + $this->assertEqual($parser->getTest(), 'myTest'); + } + + function testCanReadShortForms() { + $parser = new SimpleCommandLineParser(array('-t', 'myTest', '-c', 'MyClass', '-x')); + $this->assertEqual($parser->getTest(), 'myTest'); + $this->assertEqual($parser->getTestCase(), 'MyClass'); + $this->assertTrue($parser->isXml()); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/compatibility_test.php b/application/libraries/simpletest/test/compatibility_test.php new file mode 100644 index 00000000000..b8635e5bb83 --- /dev/null +++ b/application/libraries/simpletest/test/compatibility_test.php @@ -0,0 +1,87 @@ +assertTrue(SimpleTestCompatibility::isA( + new ComparisonClass(), + 'ComparisonClass')); + $this->assertFalse(SimpleTestCompatibility::isA( + new ComparisonClass(), + 'ComparisonSubclass')); + $this->assertTrue(SimpleTestCompatibility::isA( + new ComparisonSubclass(), + 'ComparisonClass')); + } + + function testIdentityOfNumericStrings() { + $numericString1 = "123"; + $numericString2 = "00123"; + $this->assertNotIdentical($numericString1, $numericString2); + } + + function testIdentityOfObjects() { + $object1 = new ComparisonClass(); + $object2 = new ComparisonClass(); + $this->assertIdentical($object1, $object2); + } + + function testReferences () { + $thing = "Hello"; + $thing_reference = &$thing; + $thing_copy = $thing; + $this->assertTrue(SimpleTestCompatibility::isReference( + $thing, + $thing)); + $this->assertTrue(SimpleTestCompatibility::isReference( + $thing, + $thing_reference)); + $this->assertFalse(SimpleTestCompatibility::isReference( + $thing, + $thing_copy)); + } + + function testObjectReferences () { + $object = new ComparisonClass(); + $object_reference = $object; + $object_copy = new ComparisonClass(); + $object_assignment = $object; + $this->assertTrue(SimpleTestCompatibility::isReference( + $object, + $object)); + $this->assertTrue(SimpleTestCompatibility::isReference( + $object, + $object_reference)); + $this->assertFalse(SimpleTestCompatibility::isReference( + $object, + $object_copy)); + if (version_compare(phpversion(), '5', '>=')) { + $this->assertTrue(SimpleTestCompatibility::isReference( + $object, + $object_assignment)); + } else { + $this->assertFalse(SimpleTestCompatibility::isReference( + $object, + $object_assignment)); + } + } + + function testInteraceComparison() { + $object = new ComparisonClassWithInterface(); + $this->assertFalse(SimpleTestCompatibility::isA( + new ComparisonClass(), + 'ComparisonInterface')); + $this->assertTrue(SimpleTestCompatibility::isA( + new ComparisonClassWithInterface(), + 'ComparisonInterface')); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/cookies_test.php b/application/libraries/simpletest/test/cookies_test.php new file mode 100644 index 00000000000..0b49e43bf9f --- /dev/null +++ b/application/libraries/simpletest/test/cookies_test.php @@ -0,0 +1,227 @@ +assertFalse($cookie->getValue()); + $this->assertEqual($cookie->getPath(), "/"); + $this->assertIdentical($cookie->getHost(), false); + $this->assertFalse($cookie->getExpiry()); + $this->assertFalse($cookie->isSecure()); + } + + function testCookieAccessors() { + $cookie = new SimpleCookie( + "name", + "value", + "/path", + "Mon, 18 Nov 2002 15:50:29 GMT", + true); + $this->assertEqual($cookie->getName(), "name"); + $this->assertEqual($cookie->getValue(), "value"); + $this->assertEqual($cookie->getPath(), "/path/"); + $this->assertEqual($cookie->getExpiry(), "Mon, 18 Nov 2002 15:50:29 GMT"); + $this->assertTrue($cookie->isSecure()); + } + + function testFullHostname() { + $cookie = new SimpleCookie("name"); + $this->assertTrue($cookie->setHost("host.name.here")); + $this->assertEqual($cookie->getHost(), "host.name.here"); + $this->assertTrue($cookie->setHost("host.com")); + $this->assertEqual($cookie->getHost(), "host.com"); + } + + function testHostTruncation() { + $cookie = new SimpleCookie("name"); + $cookie->setHost("this.host.name.here"); + $this->assertEqual($cookie->getHost(), "host.name.here"); + $cookie->setHost("this.host.com"); + $this->assertEqual($cookie->getHost(), "host.com"); + $this->assertTrue($cookie->setHost("dashes.in-host.com")); + $this->assertEqual($cookie->getHost(), "in-host.com"); + } + + function testBadHosts() { + $cookie = new SimpleCookie("name"); + $this->assertFalse($cookie->setHost("gibberish")); + $this->assertFalse($cookie->setHost("host.here")); + $this->assertFalse($cookie->setHost("host..com")); + $this->assertFalse($cookie->setHost("...")); + $this->assertFalse($cookie->setHost("host.com.")); + } + + function testHostValidity() { + $cookie = new SimpleCookie("name"); + $cookie->setHost("this.host.name.here"); + $this->assertTrue($cookie->isValidHost("host.name.here")); + $this->assertTrue($cookie->isValidHost("that.host.name.here")); + $this->assertFalse($cookie->isValidHost("bad.host")); + $this->assertFalse($cookie->isValidHost("nearly.name.here")); + } + + function testPathValidity() { + $cookie = new SimpleCookie("name", "value", "/path"); + $this->assertFalse($cookie->isValidPath("/")); + $this->assertTrue($cookie->isValidPath("/path/")); + $this->assertTrue($cookie->isValidPath("/path/more")); + } + + function testSessionExpiring() { + $cookie = new SimpleCookie("name", "value", "/path"); + $this->assertTrue($cookie->isExpired(0)); + } + + function testTimestampExpiry() { + $cookie = new SimpleCookie("name", "value", "/path", 456); + $this->assertFalse($cookie->isExpired(0)); + $this->assertTrue($cookie->isExpired(457)); + $this->assertFalse($cookie->isExpired(455)); + } + + function testDateExpiry() { + $cookie = new SimpleCookie( + "name", + "value", + "/path", + "Mon, 18 Nov 2002 15:50:29 GMT"); + $this->assertTrue($cookie->isExpired("Mon, 18 Nov 2002 15:50:30 GMT")); + $this->assertFalse($cookie->isExpired("Mon, 18 Nov 2002 15:50:28 GMT")); + } + + function testAging() { + $cookie = new SimpleCookie("name", "value", "/path", 200); + $cookie->agePrematurely(199); + $this->assertFalse($cookie->isExpired(0)); + $cookie->agePrematurely(2); + $this->assertTrue($cookie->isExpired(0)); + } +} + +class TestOfCookieJar extends UnitTestCase { + + function testAddCookie() { + $jar = new SimpleCookieJar(); + $jar->setCookie("a", "A"); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); + } + + function testHostFilter() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', 'my-host.com'); + $jar->setCookie('b', 'B', 'another-host.com'); + $jar->setCookie('c', 'C'); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('my-host.com')), + array('a=A', 'c=C')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('another-host.com')), + array('b=B', 'c=C')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('www.another-host.com')), + array('b=B', 'c=C')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('new-host.org')), + array('c=C')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('/')), + array('a=A', 'b=B', 'c=C')); + } + + function testPathFilter() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', false, '/path/'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/elsewhere')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array('a=A')); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array('a=A')); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/here')), array('a=A')); + } + + function testPathFilterDeeply() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', false, '/path/more_path/'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array()); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/')), array('a=A')); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/and_more')), array('a=A')); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/not_here/')), array()); + } + + function testMultipleCookieWithDifferentPathsButSameName() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'abc', false, '/'); + $jar->setCookie('a', '123', false, '/path/here/'); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('/')), + array('a=abc')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('my-host.com/')), + array('a=abc')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('my-host.com/path/')), + array('a=abc')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here')), + array('a=abc', 'a=123')); + $this->assertEqual( + $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here/there')), + array('a=abc', 'a=123')); + } + + function testOverwrite() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'abc', false, '/'); + $jar->setCookie('a', 'cde', false, '/'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=cde')); + } + + function testClearSessionCookies() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', false, '/'); + $jar->restartSession(); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); + } + + function testExpiryFilterByDate() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT'); + $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); + $jar->restartSession("Wed, 25-Dec-02 04:24:21 GMT"); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); + } + + function testExpiryFilterByAgeing() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT'); + $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A')); + $jar->agePrematurely(2); + $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT"); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); + } + + function testCookieClearing() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'abc', false, '/'); + $jar->setCookie('a', '', false, '/'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=')); + } + + function testCookieClearByLoweringDate() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'abc', false, '/', 'Wed, 25-Dec-02 04:24:21 GMT'); + $jar->setCookie('a', 'def', false, '/', 'Wed, 25-Dec-02 04:24:19 GMT'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=def')); + $jar->restartSession('Wed, 25-Dec-02 04:24:20 GMT'); + $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array()); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/detached_test.php b/application/libraries/simpletest/test/detached_test.php new file mode 100644 index 00000000000..f651d97eb61 --- /dev/null +++ b/application/libraries/simpletest/test/detached_test.php @@ -0,0 +1,15 @@ +add(new DetachedTestCase($command)); +if (SimpleReporter::inCli()) { + exit ($test->run(new TextReporter()) ? 0 : 1); +} +$test->run(new HtmlReporter()); +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/dumper_test.php b/application/libraries/simpletest/test/dumper_test.php new file mode 100644 index 00000000000..789047de924 --- /dev/null +++ b/application/libraries/simpletest/test/dumper_test.php @@ -0,0 +1,88 @@ +assertEqual( + $dumper->clipString("Hello", 6), + "Hello", + "Hello, 6->%s"); + $this->assertEqual( + $dumper->clipString("Hello", 5), + "Hello", + "Hello, 5->%s"); + $this->assertEqual( + $dumper->clipString("Hello world", 3), + "Hel...", + "Hello world, 3->%s"); + $this->assertEqual( + $dumper->clipString("Hello world", 6, 3), + "Hello ...", + "Hello world, 6, 3->%s"); + $this->assertEqual( + $dumper->clipString("Hello world", 3, 6), + "...o w...", + "Hello world, 3, 6->%s"); + $this->assertEqual( + $dumper->clipString("Hello world", 4, 11), + "...orld", + "Hello world, 4, 11->%s"); + $this->assertEqual( + $dumper->clipString("Hello world", 4, 12), + "...orld", + "Hello world, 4, 12->%s"); + } + + function testDescribeNull() { + $dumper = new SimpleDumper(); + $this->assertPattern('/null/i', $dumper->describeValue(null)); + } + + function testDescribeBoolean() { + $dumper = new SimpleDumper(); + $this->assertPattern('/boolean/i', $dumper->describeValue(true)); + $this->assertPattern('/true/i', $dumper->describeValue(true)); + $this->assertPattern('/false/i', $dumper->describeValue(false)); + } + + function testDescribeString() { + $dumper = new SimpleDumper(); + $this->assertPattern('/string/i', $dumper->describeValue('Hello')); + $this->assertPattern('/Hello/', $dumper->describeValue('Hello')); + } + + function testDescribeInteger() { + $dumper = new SimpleDumper(); + $this->assertPattern('/integer/i', $dumper->describeValue(35)); + $this->assertPattern('/35/', $dumper->describeValue(35)); + } + + function testDescribeFloat() { + $dumper = new SimpleDumper(); + $this->assertPattern('/float/i', $dumper->describeValue(0.99)); + $this->assertPattern('/0\.99/', $dumper->describeValue(0.99)); + } + + function testDescribeArray() { + $dumper = new SimpleDumper(); + $this->assertPattern('/array/i', $dumper->describeValue(array(1, 4))); + $this->assertPattern('/2/i', $dumper->describeValue(array(1, 4))); + } + + function testDescribeObject() { + $dumper = new SimpleDumper(); + $this->assertPattern( + '/object/i', + $dumper->describeValue(new DumperDummy())); + $this->assertPattern( + '/DumperDummy/i', + $dumper->describeValue(new DumperDummy())); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/eclipse_test.php b/application/libraries/simpletest/test/eclipse_test.php new file mode 100644 index 00000000000..c90cbc918fd --- /dev/null +++ b/application/libraries/simpletest/test/eclipse_test.php @@ -0,0 +1,32 @@ +expectOnce('write',array($expected)); + $listener->setReturnValue('write',-1); + + $pathparts = pathinfo($fullpath); + $filename = $pathparts['basename']; + $test= &new TestSuite($filename); + $test->addTestFile($fullpath); + $test->run(new EclipseReporter($listener)); + $this->assertEqual($expected,$listener->output); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/encoding_test.php b/application/libraries/simpletest/test/encoding_test.php new file mode 100644 index 00000000000..a09236e057c --- /dev/null +++ b/application/libraries/simpletest/test/encoding_test.php @@ -0,0 +1,240 @@ +assertEqual($pair->asRequest(), 'a=A'); + } + + function testMimeEncodedAsHeadersAndContent() { + $pair = new SimpleEncodedPair('a', 'A'); + $this->assertEqual( + $pair->asMime(), + "Content-Disposition: form-data; name=\"a\"\r\n\r\nA"); + } + + function testAttachmentEncodedAsHeadersWithDispositionAndContent() { + $part = new SimpleAttachment('a', 'A', 'aaa.txt'); + $this->assertEqual( + $part->asMime(), + "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" . + "Content-Type: text/plain\r\n\r\nA"); + } +} + +class TestOfEncoding extends UnitTestCase { + private $content_so_far; + + function write($content) { + $this->content_so_far .= $content; + } + + function clear() { + $this->content_so_far = ''; + } + + function assertWritten($encoding, $content, $message = '%s') { + $this->clear(); + $encoding->writeTo($this); + $this->assertIdentical($this->content_so_far, $content, $message); + } + + function testGetEmpty() { + $encoding = new SimpleGetEncoding(); + $this->assertIdentical($encoding->getValue('a'), false); + $this->assertIdentical($encoding->asUrlRequest(), ''); + } + + function testPostEmpty() { + $encoding = new SimplePostEncoding(); + $this->assertIdentical($encoding->getValue('a'), false); + $this->assertWritten($encoding, ''); + } + + function testPrefilled() { + $encoding = new SimplePostEncoding(array('a' => 'aaa')); + $this->assertIdentical($encoding->getValue('a'), 'aaa'); + $this->assertWritten($encoding, 'a=aaa'); + } + + function testPrefilledWithTwoLevels() { + $query = array('a' => array('aa' => 'aaa')); + $encoding = new SimplePostEncoding($query); + $this->assertTrue($encoding->hasMoreThanOneLevel($query)); + $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[aa]' => 'aaa')); + $this->assertIdentical($encoding->getValue('a[aa]'), 'aaa'); + $this->assertWritten($encoding, 'a%5Baa%5D=aaa'); + } + + function testPrefilledWithThreeLevels() { + $query = array('a' => array('aa' => array('aaa' => 'aaaa'))); + $encoding = new SimplePostEncoding($query); + $this->assertTrue($encoding->hasMoreThanOneLevel($query)); + $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[aa][aaa]' => 'aaaa')); + $this->assertIdentical($encoding->getValue('a[aa][aaa]'), 'aaaa'); + $this->assertWritten($encoding, 'a%5Baa%5D%5Baaa%5D=aaaa'); + } + + function testPrefilledWithObject() { + $encoding = new SimplePostEncoding(new SimpleEncoding(array('a' => 'aaa'))); + $this->assertIdentical($encoding->getValue('a'), 'aaa'); + $this->assertWritten($encoding, 'a=aaa'); + } + + function testMultiplePrefilled() { + $query = array('a' => array('a1', 'a2')); + $encoding = new SimplePostEncoding($query); + $this->assertTrue($encoding->hasMoreThanOneLevel($query)); + $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[0]' => 'a1', 'a[1]' => 'a2')); + $this->assertIdentical($encoding->getValue('a[0]'), 'a1'); + $this->assertIdentical($encoding->getValue('a[1]'), 'a2'); + $this->assertWritten($encoding, 'a%5B0%5D=a1&a%5B1%5D=a2'); + } + + function testSingleParameter() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', 'Hello'); + $this->assertEqual($encoding->getValue('a'), 'Hello'); + $this->assertWritten($encoding, 'a=Hello'); + } + + function testFalseParameter() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', false); + $this->assertEqual($encoding->getValue('a'), false); + $this->assertWritten($encoding, ''); + } + + function testUrlEncoding() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', 'Hello there!'); + $this->assertWritten($encoding, 'a=Hello+there%21'); + } + + function testUrlEncodingOfKey() { + $encoding = new SimplePostEncoding(); + $encoding->add('a!', 'Hello'); + $this->assertWritten($encoding, 'a%21=Hello'); + } + + function testMultipleParameter() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', 'Hello'); + $encoding->add('b', 'Goodbye'); + $this->assertWritten($encoding, 'a=Hello&b=Goodbye'); + } + + function testEmptyParameters() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', ''); + $encoding->add('b', ''); + $this->assertWritten($encoding, 'a=&b='); + } + + function testRepeatedParameter() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', 'Hello'); + $encoding->add('a', 'Goodbye'); + $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye')); + $this->assertWritten($encoding, 'a=Hello&a=Goodbye'); + } + + function testAddingLists() { + $encoding = new SimplePostEncoding(); + $encoding->add('a', array('Hello', 'Goodbye')); + $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye')); + $this->assertWritten($encoding, 'a=Hello&a=Goodbye'); + } + + function testMergeInHash() { + $encoding = new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B')); + $encoding->merge(array('a' => 'A2')); + $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2')); + $this->assertIdentical($encoding->getValue('b'), 'B'); + } + + function testMergeInObject() { + $encoding = new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B')); + $encoding->merge(new SimpleEncoding(array('a' => 'A2'))); + $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2')); + $this->assertIdentical($encoding->getValue('b'), 'B'); + } + + function testPrefilledMultipart() { + $encoding = new SimpleMultipartEncoding(array('a' => 'aaa'), 'boundary'); + $this->assertIdentical($encoding->getValue('a'), 'aaa'); + $this->assertwritten($encoding, + "--boundary\r\n" . + "Content-Disposition: form-data; name=\"a\"\r\n" . + "\r\n" . + "aaa\r\n" . + "--boundary--\r\n"); + } + + function testAttachment() { + $encoding = new SimpleMultipartEncoding(array(), 'boundary'); + $encoding->attach('a', 'aaa', 'aaa.txt'); + $this->assertIdentical($encoding->getValue('a'), 'aaa.txt'); + $this->assertwritten($encoding, + "--boundary\r\n" . + "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" . + "Content-Type: text/plain\r\n" . + "\r\n" . + "aaa\r\n" . + "--boundary--\r\n"); + } + + function testEntityEncodingDefaultContentType() { + $encoding = new SimpleEntityEncoding(); + $this->assertIdentical($encoding->getContentType(), 'application/x-www-form-urlencoded'); + $this->assertWritten($encoding, ''); + } + + function testEntityEncodingTextBody() { + $encoding = new SimpleEntityEncoding('plain text'); + $this->assertIdentical($encoding->getContentType(), 'text/plain'); + $this->assertWritten($encoding, 'plain text'); + } + + function testEntityEncodingXmlBody() { + $encoding = new SimpleEntityEncoding('

    xmltext

    ', 'text/xml'); + $this->assertIdentical($encoding->getContentType(), 'text/xml'); + $this->assertWritten($encoding, '

    xmltext

    '); + } +} + +class TestOfEncodingHeaders extends UnitTestCase { + + function testEmptyEncodingWritesZeroContentLength() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 0\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); + $encoding = new SimpleEntityEncoding(); + $encoding->writeHeadersTo($socket); + } + + function testTextEncodingWritesDefaultContentType() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 18\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: text/plain\r\n")); + $encoding = new SimpleEntityEncoding('one two three four'); + $encoding->writeHeadersTo($socket); + } + + function testEmptyMultipartEncodingWritesEndBoundaryContentLength() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 14\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: multipart/form-data; boundary=boundary\r\n")); + $encoding = new SimpleMultipartEncoding(array(), 'boundary'); + $encoding->writeHeadersTo($socket); + } + +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/errors_test.php b/application/libraries/simpletest/test/errors_test.php new file mode 100644 index 00000000000..ebb9e05891f --- /dev/null +++ b/application/libraries/simpletest/test/errors_test.php @@ -0,0 +1,229 @@ +get('SimpleErrorQueue'); + $queue->clear(); + } + + function tearDown() { + $context = SimpleTest::getContext(); + $queue = $context->get('SimpleErrorQueue'); + $queue->clear(); + } + + function testExpectationMatchCancelsIncomingError() { + $test = new MockSimpleTestCase(); + $test->expectOnce('assert', array( + new IdenticalExpectation(new AnythingExpectation()), + 'B', + 'a message')); + $test->setReturnValue('assert', true); + $test->expectNever('error'); + $queue = new SimpleErrorQueue(); + $queue->setTestCase($test); + $queue->expectError(new AnythingExpectation(), 'a message'); + $queue->add(1024, 'B', 'b.php', 100); + } +} + +class TestOfErrorTrap extends UnitTestCase { + private $old; + + function setUp() { + $this->old = error_reporting(E_ALL); + set_error_handler('SimpleTestErrorHandler'); + } + + function tearDown() { + restore_error_handler(); + error_reporting($this->old); + } + + function testQueueStartsEmpty() { + $context = SimpleTest::getContext(); + $queue = $context->get('SimpleErrorQueue'); + $this->assertFalse($queue->extract()); + } + + function testErrorsAreSwallowedByMatchingExpectation() { + $this->expectError('Ouch!'); + trigger_error('Ouch!'); + } + + function testErrorsAreSwallowedInOrder() { + $this->expectError('a'); + $this->expectError('b'); + trigger_error('a'); + trigger_error('b'); + } + + function testAnyErrorCanBeSwallowed() { + $this->expectError(); + trigger_error('Ouch!'); + } + + function testErrorCanBeSwallowedByPatternMatching() { + $this->expectError(new PatternExpectation('/ouch/i')); + trigger_error('Ouch!'); + } + + function testErrorWithPercentsPassesWithNoSprintfError() { + $this->expectError("%"); + trigger_error('%'); + } +} + +class TestOfErrors extends UnitTestCase { + private $old; + + function setUp() { + $this->old = error_reporting(E_ALL); + } + + function tearDown() { + error_reporting($this->old); + } + + function testDefaultWhenAllReported() { + error_reporting(E_ALL); + $this->expectError('Ouch!'); + trigger_error('Ouch!'); + } + + function testNoticeWhenReported() { + error_reporting(E_ALL); + $this->expectError('Ouch!'); + trigger_error('Ouch!', E_USER_NOTICE); + } + + function testWarningWhenReported() { + error_reporting(E_ALL); + $this->expectError('Ouch!'); + trigger_error('Ouch!', E_USER_WARNING); + } + + function testErrorWhenReported() { + error_reporting(E_ALL); + $this->expectError('Ouch!'); + trigger_error('Ouch!', E_USER_ERROR); + } + + function testNoNoticeWhenNotReported() { + error_reporting(0); + trigger_error('Ouch!', E_USER_NOTICE); + } + + function testNoWarningWhenNotReported() { + error_reporting(0); + trigger_error('Ouch!', E_USER_WARNING); + } + + function testNoticeSuppressedWhenReported() { + error_reporting(E_ALL); + @trigger_error('Ouch!', E_USER_NOTICE); + } + + function testWarningSuppressedWhenReported() { + error_reporting(E_ALL); + @trigger_error('Ouch!', E_USER_WARNING); + } + + function testErrorWithPercentsReportedWithNoSprintfError() { + $this->expectError('%'); + trigger_error('%'); + } +} + +class TestOfPHP52RecoverableErrors extends UnitTestCase { + function skip() { + $this->skipIf( + version_compare(phpversion(), '5.2', '<'), + 'E_RECOVERABLE_ERROR not tested for PHP below 5.2'); + } + + function testError() { + eval(' + class RecoverableErrorTestingStub { + function ouch(RecoverableErrorTestingStub $obj) { + } + } + '); + + $stub = new RecoverableErrorTestingStub(); + $this->expectError(new PatternExpectation('/must be an instance of RecoverableErrorTestingStub/i')); + $stub->ouch(new stdClass()); + } +} + +class TestOfErrorsExcludingPHP52AndAbove extends UnitTestCase { + function skip() { + $this->skipIf( + version_compare(phpversion(), '5.2', '>='), + 'E_USER_ERROR not tested for PHP 5.2 and above'); + } + + function testNoErrorWhenNotReported() { + error_reporting(0); + trigger_error('Ouch!', E_USER_ERROR); + } + + function testErrorSuppressedWhenReported() { + error_reporting(E_ALL); + @trigger_error('Ouch!', E_USER_ERROR); + } +} + +SimpleTest::ignore('TestOfNotEnoughErrors'); +/** + * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors} + * to verify that it fails as expected. + * + * @ignore + */ +class TestOfNotEnoughErrors extends UnitTestCase { + function testExpectTwoErrorsThrowOne() { + $this->expectError('Error 1'); + trigger_error('Error 1'); + $this->expectError('Error 2'); + } +} + +SimpleTest::ignore('TestOfLeftOverErrors'); +/** + * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors} + * to verify that it fails as expected. + * + * @ignore + */ +class TestOfLeftOverErrors extends UnitTestCase { + function testExpectOneErrorGetTwo() { + $this->expectError('Error 1'); + trigger_error('Error 1'); + trigger_error('Error 2'); + } +} + +class TestRunnerForLeftOverAndNotEnoughErrors extends UnitTestCase { + function testRunLeftOverErrorsTestCase() { + $test = new TestOfLeftOverErrors(); + $this->assertFalse($test->run(new SimpleReporter())); + } + + function testRunNotEnoughErrors() { + $test = new TestOfNotEnoughErrors(); + $this->assertFalse($test->run(new SimpleReporter())); + } +} + +// TODO: Add stacked error handler test +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/exceptions_test.php b/application/libraries/simpletest/test/exceptions_test.php new file mode 100644 index 00000000000..1011543d4fa --- /dev/null +++ b/application/libraries/simpletest/test/exceptions_test.php @@ -0,0 +1,183 @@ +assertTrue($expectation->test(new MyTestException())); + $this->assertTrue($expectation->test(new HigherTestException())); + $this->assertFalse($expectation->test(new OtherTestException())); + } + + function testMatchesClassAndMessageWhenExceptionExpected() { + $expectation = new ExceptionExpectation(new MyTestException('Hello')); + $this->assertTrue($expectation->test(new MyTestException('Hello'))); + $this->assertFalse($expectation->test(new HigherTestException('Hello'))); + $this->assertFalse($expectation->test(new OtherTestException('Hello'))); + $this->assertFalse($expectation->test(new MyTestException('Goodbye'))); + $this->assertFalse($expectation->test(new MyTestException())); + } + + function testMessagelessExceptionMatchesOnlyOnClass() { + $expectation = new ExceptionExpectation(new MyTestException()); + $this->assertTrue($expectation->test(new MyTestException())); + $this->assertFalse($expectation->test(new HigherTestException())); + } +} + +class TestOfExceptionTrap extends UnitTestCase { + + function testNoExceptionsInQueueMeansNoTestMessages() { + $test = new MockSimpleTestCase(); + $test->expectNever('assert'); + $queue = new SimpleExceptionTrap(); + $this->assertFalse($queue->isExpected($test, new Exception())); + } + + function testMatchingExceptionGivesTrue() { + $expectation = new MockSimpleExpectation(); + $expectation->setReturnValue('test', true); + $test = new MockSimpleTestCase(); + $test->setReturnValue('assert', true); + $queue = new SimpleExceptionTrap(); + $queue->expectException($expectation, 'message'); + $this->assertTrue($queue->isExpected($test, new Exception())); + } + + function testMatchingExceptionTriggersAssertion() { + $test = new MockSimpleTestCase(); + $test->expectOnce('assert', array( + '*', + new ExceptionExpectation(new Exception()), + 'message')); + $queue = new SimpleExceptionTrap(); + $queue->expectException(new ExceptionExpectation(new Exception()), 'message'); + $queue->isExpected($test, new Exception()); + } +} + +class TestOfCatchingExceptions extends UnitTestCase { + + function testCanCatchAnyExpectedException() { + $this->expectException(); + throw new Exception(); + } + + function testCanMatchExceptionByClass() { + $this->expectException('MyTestException'); + throw new HigherTestException(); + } + + function testCanMatchExceptionExactly() { + $this->expectException(new Exception('Ouch')); + throw new Exception('Ouch'); + } + + function testLastListedExceptionIsTheOneThatCounts() { + $this->expectException('OtherTestException'); + $this->expectException('MyTestException'); + throw new HigherTestException(); + } +} + +class TestOfIgnoringExceptions extends UnitTestCase { + + function testCanIgnoreAnyException() { + $this->ignoreException(); + throw new Exception(); + } + + function testCanIgnoreSpecificException() { + $this->ignoreException('MyTestException'); + throw new MyTestException(); + } + + function testCanIgnoreExceptionExactly() { + $this->ignoreException(new Exception('Ouch')); + throw new Exception('Ouch'); + } + + function testIgnoredExceptionsDoNotMaskExpectedExceptions() { + $this->ignoreException('Exception'); + $this->expectException('MyTestException'); + throw new MyTestException(); + } + + function testCanIgnoreMultipleExceptions() { + $this->ignoreException('MyTestException'); + $this->ignoreException('OtherTestException'); + throw new OtherTestException(); + } +} + +class TestOfCallingTearDownAfterExceptions extends UnitTestCase { + private $debri = 0; + + function tearDown() { + $this->debri--; + } + + function testLeaveSomeDebri() { + $this->debri++; + $this->expectException(); + throw new Exception(__FUNCTION__); + } + + function testDebriWasRemovedOnce() { + $this->assertEqual($this->debri, 0); + } +} + +class TestOfExceptionThrownInSetUpDoesNotRunTestBody extends UnitTestCase { + + function setUp() { + $this->expectException(); + throw new Exception(); + } + + function testShouldNotBeRun() { + $this->fail('This test body should not be run'); + } + + function testShouldNotBeRunEither() { + $this->fail('This test body should not be run either'); + } +} + +class TestOfExpectExceptionWithSetUp extends UnitTestCase { + + function setUp() { + $this->expectException(); + } + + function testThisExceptionShouldBeCaught() { + throw new Exception(); + } + + function testJustThrowingMyTestException() { + throw new MyTestException(); + } +} + +class TestOfThrowingExceptionsInTearDown extends UnitTestCase { + + function tearDown() { + throw new Exception(); + } + + function testDoesntFatal() { + $this->expectException(); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/expectation_test.php b/application/libraries/simpletest/test/expectation_test.php new file mode 100644 index 00000000000..31fbe65e683 --- /dev/null +++ b/application/libraries/simpletest/test/expectation_test.php @@ -0,0 +1,317 @@ +assertTrue($is_true->test(true)); + $this->assertFalse($is_true->test(false)); + } + + function testStringMatch() { + $hello = new EqualExpectation("Hello"); + $this->assertTrue($hello->test("Hello")); + $this->assertFalse($hello->test("Goodbye")); + } + + function testInteger() { + $fifteen = new EqualExpectation(15); + $this->assertTrue($fifteen->test(15)); + $this->assertFalse($fifteen->test(14)); + } + + function testFloat() { + $pi = new EqualExpectation(3.14); + $this->assertTrue($pi->test(3.14)); + $this->assertFalse($pi->test(3.15)); + } + + function testArray() { + $colours = new EqualExpectation(array("r", "g", "b")); + $this->assertTrue($colours->test(array("r", "g", "b"))); + $this->assertFalse($colours->test(array("g", "b", "r"))); + } + + function testHash() { + $is_blue = new EqualExpectation(array("r" => 0, "g" => 0, "b" => 255)); + $this->assertTrue($is_blue->test(array("r" => 0, "g" => 0, "b" => 255))); + $this->assertFalse($is_blue->test(array("r" => 0, "g" => 255, "b" => 0))); + } + + function testHashWithOutOfOrderKeysShouldStillMatch() { + $any_order = new EqualExpectation(array('a' => 1, 'b' => 2)); + $this->assertTrue($any_order->test(array('b' => 2, 'a' => 1))); + } +} + +class TestOfWithin extends UnitTestCase { + + function testWithinFloatingPointMargin() { + $within = new WithinMarginExpectation(1.0, 0.2); + $this->assertFalse($within->test(0.7)); + $this->assertTrue($within->test(0.8)); + $this->assertTrue($within->test(0.9)); + $this->assertTrue($within->test(1.1)); + $this->assertTrue($within->test(1.2)); + $this->assertFalse($within->test(1.3)); + } + + function testOutsideFloatingPointMargin() { + $within = new OutsideMarginExpectation(1.0, 0.2); + $this->assertTrue($within->test(0.7)); + $this->assertFalse($within->test(0.8)); + $this->assertFalse($within->test(1.2)); + $this->assertTrue($within->test(1.3)); + } +} + +class TestOfInequality extends UnitTestCase { + + function testStringMismatch() { + $not_hello = new NotEqualExpectation("Hello"); + $this->assertTrue($not_hello->test("Goodbye")); + $this->assertFalse($not_hello->test("Hello")); + } +} + +class RecursiveNasty { + private $me; + + function RecursiveNasty() { + $this->me = $this; + } +} + +class OpaqueContainer { + private $stuff; + private $value; + + public function __construct($value) { + $this->value = $value; + } +} + +class DerivedOpaqueContainer extends OpaqueContainer { + // Deliberately have a variable whose name with the same suffix as a later + // variable + private $new_value = 1; + + // Deliberately obscures the variable of the same name in the base + // class. + private $value; + + public function __construct($value, $base_value) { + parent::__construct($base_value); + $this->value = $value; + } +} + +class TestOfIdentity extends UnitTestCase { + + function testType() { + $string = new IdenticalExpectation("37"); + $this->assertTrue($string->test("37")); + $this->assertFalse($string->test(37)); + $this->assertFalse($string->test("38")); + } + + function _testNastyPhp5Bug() { + $this->assertFalse(new RecursiveNasty() != new RecursiveNasty()); + } + + function _testReallyHorribleRecursiveStructure() { + $hopeful = new IdenticalExpectation(new RecursiveNasty()); + $this->assertTrue($hopeful->test(new RecursiveNasty())); + } + + function testCanComparePrivateMembers() { + $expectFive = new IdenticalExpectation(new OpaqueContainer(5)); + $this->assertTrue($expectFive->test(new OpaqueContainer(5))); + $this->assertFalse($expectFive->test(new OpaqueContainer(6))); + } + + function testCanComparePrivateMembersOfObjectsInArrays() { + $expectFive = new IdenticalExpectation(array(new OpaqueContainer(5))); + $this->assertTrue($expectFive->test(array(new OpaqueContainer(5)))); + $this->assertFalse($expectFive->test(array(new OpaqueContainer(6)))); + } + + function testCanComparePrivateMembersOfObjectsWherePrivateMemberOfBaseClassIsObscured() { + $expectFive = new IdenticalExpectation(array(new DerivedOpaqueContainer(1,2))); + $this->assertTrue($expectFive->test(array(new DerivedOpaqueContainer(1,2)))); + $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(0,2)))); + $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(0,9)))); + $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(1,0)))); + } +} + +class TransparentContainer { + public $value; + + public function __construct($value) { + $this->value = $value; + } +} + +class TestOfMemberComparison extends UnitTestCase { + + function testMemberExpectationCanMatchPublicMember() { + $expect_five = new MemberExpectation('value', 5); + $this->assertTrue($expect_five->test(new TransparentContainer(5))); + $this->assertFalse($expect_five->test(new TransparentContainer(8))); + } + + function testMemberExpectationCanMatchPrivateMember() { + $expect_five = new MemberExpectation('value', 5); + $this->assertTrue($expect_five->test(new OpaqueContainer(5))); + $this->assertFalse($expect_five->test(new OpaqueContainer(8))); + } + + function testMemberExpectationCanMatchPrivateMemberObscuredByDerivedClass() { + $expect_five = new MemberExpectation('value', 5); + $this->assertTrue($expect_five->test(new DerivedOpaqueContainer(5,8))); + $this->assertTrue($expect_five->test(new DerivedOpaqueContainer(5,5))); + $this->assertFalse($expect_five->test(new DerivedOpaqueContainer(8,8))); + $this->assertFalse($expect_five->test(new DerivedOpaqueContainer(8,5))); + } + +} + +class DummyReferencedObject{} + +class TestOfReference extends UnitTestCase { + + function testReference() { + $foo = "foo"; + $ref = &$foo; + $not_ref = $foo; + $bar = "bar"; + + $expect = new ReferenceExpectation($foo); + $this->assertTrue($expect->test($ref)); + $this->assertFalse($expect->test($not_ref)); + $this->assertFalse($expect->test($bar)); + } +} + +class TestOfNonIdentity extends UnitTestCase { + + function testType() { + $string = new NotIdenticalExpectation("37"); + $this->assertTrue($string->test("38")); + $this->assertTrue($string->test(37)); + $this->assertFalse($string->test("37")); + } +} + +class TestOfPatterns extends UnitTestCase { + + function testWanted() { + $pattern = new PatternExpectation('/hello/i'); + $this->assertTrue($pattern->test("Hello world")); + $this->assertFalse($pattern->test("Goodbye world")); + } + + function testUnwanted() { + $pattern = new NoPatternExpectation('/hello/i'); + $this->assertFalse($pattern->test("Hello world")); + $this->assertTrue($pattern->test("Goodbye world")); + } +} + +class ExpectedMethodTarget { + function hasThisMethod() {} +} + +class TestOfMethodExistence extends UnitTestCase { + + function testHasMethod() { + $instance = new ExpectedMethodTarget(); + $expectation = new MethodExistsExpectation('hasThisMethod'); + $this->assertTrue($expectation->test($instance)); + $expectation = new MethodExistsExpectation('doesNotHaveThisMethod'); + $this->assertFalse($expectation->test($instance)); + } +} + +class TestOfIsA extends UnitTestCase { + + function testString() { + $expectation = new IsAExpectation('string'); + $this->assertTrue($expectation->test('Hello')); + $this->assertFalse($expectation->test(5)); + } + + function testBoolean() { + $expectation = new IsAExpectation('boolean'); + $this->assertTrue($expectation->test(true)); + $this->assertFalse($expectation->test(1)); + } + + function testBool() { + $expectation = new IsAExpectation('bool'); + $this->assertTrue($expectation->test(true)); + $this->assertFalse($expectation->test(1)); + } + + function testDouble() { + $expectation = new IsAExpectation('double'); + $this->assertTrue($expectation->test(5.0)); + $this->assertFalse($expectation->test(5)); + } + + function testFloat() { + $expectation = new IsAExpectation('float'); + $this->assertTrue($expectation->test(5.0)); + $this->assertFalse($expectation->test(5)); + } + + function testReal() { + $expectation = new IsAExpectation('real'); + $this->assertTrue($expectation->test(5.0)); + $this->assertFalse($expectation->test(5)); + } + + function testInteger() { + $expectation = new IsAExpectation('integer'); + $this->assertTrue($expectation->test(5)); + $this->assertFalse($expectation->test(5.0)); + } + + function testInt() { + $expectation = new IsAExpectation('int'); + $this->assertTrue($expectation->test(5)); + $this->assertFalse($expectation->test(5.0)); + } + + function testScalar() { + $expectation = new IsAExpectation('scalar'); + $this->assertTrue($expectation->test(5)); + $this->assertFalse($expectation->test(array(5))); + } + + function testNumeric() { + $expectation = new IsAExpectation('numeric'); + $this->assertTrue($expectation->test(5)); + $this->assertFalse($expectation->test('string')); + } + + function testNull() { + $expectation = new IsAExpectation('null'); + $this->assertTrue($expectation->test(null)); + $this->assertFalse($expectation->test('string')); + } +} + +class TestOfNotA extends UnitTestCase { + + function testString() { + $expectation = new NotAExpectation('string'); + $this->assertFalse($expectation->test('Hello')); + $this->assertTrue($expectation->test(5)); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/form_test.php b/application/libraries/simpletest/test/form_test.php new file mode 100644 index 00000000000..70a18f2b3a0 --- /dev/null +++ b/application/libraries/simpletest/test/form_test.php @@ -0,0 +1,344 @@ +returns('getUrl', new SimpleUrl($url)); + $page->returns('expandUrl', new SimpleUrl($url)); + return $page; + } + + function testFormAttributes() { + $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php', 'id' => '33')); + $form = new SimpleForm($tag, $this->page('http://host/a/index.html')); + $this->assertEqual($form->getMethod(), 'get'); + $this->assertIdentical($form->getId(), '33'); + $this->assertNull($form->getValue(new SimpleByName('a'))); + } + + function testAction() { + $page = new MockSimplePage(); + $page->expectOnce('expandUrl', array(new SimpleUrl('here.php'))); + $page->setReturnValue('expandUrl', new SimpleUrl('http://host/here.php')); + $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php')); + $form = new SimpleForm($tag, $page); + $this->assertEqual($form->getAction(), new SimpleUrl('http://host/here.php')); + } + + function testEmptyAction() { + $tag = new SimpleFormTag(array('method' => 'GET', 'action' => '', 'id' => '33')); + $form = new SimpleForm($tag, $this->page('http://host/a/index.html')); + $this->assertEqual( + $form->getAction(), + new SimpleUrl('http://host/a/index.html')); + } + + function testMissingAction() { + $tag = new SimpleFormTag(array('method' => 'GET')); + $form = new SimpleForm($tag, $this->page('http://host/a/index.html')); + $this->assertEqual( + $form->getAction(), + new SimpleUrl('http://host/a/index.html')); + } + + function testRootAction() { + $page = new MockSimplePage(); + $page->expectOnce('expandUrl', array(new SimpleUrl('/'))); + $page->setReturnValue('expandUrl', new SimpleUrl('http://host/')); + $tag = new SimpleFormTag(array('method' => 'GET', 'action' => '/')); + $form = new SimpleForm($tag, $page); + $this->assertEqual( + $form->getAction(), + new SimpleUrl('http://host/')); + } + + function testDefaultFrameTargetOnForm() { + $page = new MockSimplePage(); + $page->expectOnce('expandUrl', array(new SimpleUrl('here.php'))); + $page->setReturnValue('expandUrl', new SimpleUrl('http://host/here.php')); + $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php')); + $form = new SimpleForm($tag, $page); + $form->setDefaultTarget('frame'); + $expected = new SimpleUrl('http://host/here.php'); + $expected->setTarget('frame'); + $this->assertEqual($form->getAction(), $expected); + } + + function testTextWidget() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleTextTag( + array('name' => 'me', 'type' => 'text', 'value' => 'Myself'))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Myself'); + $this->assertTrue($form->setField(new SimpleByName('me'), 'Not me')); + $this->assertFalse($form->setField(new SimpleByName('not_present'), 'Not me')); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Not me'); + $this->assertNull($form->getValue(new SimpleByName('not_present'))); + } + + function testTextWidgetById() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleTextTag( + array('name' => 'me', 'type' => 'text', 'value' => 'Myself', 'id' => 50))); + $this->assertIdentical($form->getValue(new SimpleById(50)), 'Myself'); + $this->assertTrue($form->setField(new SimpleById(50), 'Not me')); + $this->assertIdentical($form->getValue(new SimpleById(50)), 'Not me'); + } + + function testTextWidgetByLabel() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $widget = new SimpleTextTag(array('name' => 'me', 'type' => 'text', 'value' => 'a')); + $form->addWidget($widget); + $widget->setLabel('thing'); + $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'a'); + $this->assertTrue($form->setField(new SimpleByLabel('thing'), 'b')); + $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'b'); + } + + function testSubmitEmpty() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $this->assertIdentical($form->submit(), new SimpleGetEncoding()); + } + + function testSubmitButton() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host')); + $form->addWidget(new SimpleSubmitTag( + array('type' => 'submit', 'name' => 'go', 'value' => 'Go!', 'id' => '9'))); + $this->assertTrue($form->hasSubmit(new SimpleByName('go'))); + $this->assertEqual($form->getValue(new SimpleByName('go')), 'Go!'); + $this->assertEqual($form->getValue(new SimpleById(9)), 'Go!'); + $this->assertEqual( + $form->submitButton(new SimpleByName('go')), + new SimpleGetEncoding(array('go' => 'Go!'))); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Go!')), + new SimpleGetEncoding(array('go' => 'Go!'))); + $this->assertEqual( + $form->submitButton(new SimpleById(9)), + new SimpleGetEncoding(array('go' => 'Go!'))); + } + + function testSubmitWithAdditionalParameters() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host')); + $form->addWidget(new SimpleSubmitTag( + array('type' => 'submit', 'name' => 'go', 'value' => 'Go!'))); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Go!'), array('a' => 'A')), + new SimpleGetEncoding(array('go' => 'Go!', 'a' => 'A'))); + } + + function testSubmitButtonWithLabelOfSubmit() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host')); + $form->addWidget(new SimpleSubmitTag( + array('type' => 'submit', 'name' => 'test', 'value' => 'Submit'))); + $this->assertEqual( + $form->submitButton(new SimpleByName('test')), + new SimpleGetEncoding(array('test' => 'Submit'))); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Submit')), + new SimpleGetEncoding(array('test' => 'Submit'))); + } + + function testSubmitButtonWithWhitespacePaddedLabelOfSubmit() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host')); + $form->addWidget(new SimpleSubmitTag( + array('type' => 'submit', 'name' => 'test', 'value' => ' Submit '))); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Submit')), + new SimpleGetEncoding(array('test' => ' Submit '))); + } + + function testImageSubmitButton() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleImageSubmitTag(array( + 'type' => 'image', + 'src' => 'source.jpg', + 'name' => 'go', + 'alt' => 'Go!', + 'id' => '9'))); + $this->assertTrue($form->hasImage(new SimpleByLabel('Go!'))); + $this->assertEqual( + $form->submitImage(new SimpleByLabel('Go!'), 100, 101), + new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); + $this->assertTrue($form->hasImage(new SimpleByName('go'))); + $this->assertEqual( + $form->submitImage(new SimpleByName('go'), 100, 101), + new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); + $this->assertTrue($form->hasImage(new SimpleById(9))); + $this->assertEqual( + $form->submitImage(new SimpleById(9), 100, 101), + new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101))); + } + + function testImageSubmitButtonWithAdditionalData() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleImageSubmitTag(array( + 'type' => 'image', + 'src' => 'source.jpg', + 'name' => 'go', + 'alt' => 'Go!'))); + $this->assertEqual( + $form->submitImage(new SimpleByLabel('Go!'), 100, 101, array('a' => 'A')), + new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101, 'a' => 'A'))); + } + + function testButtonTag() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host')); + $widget = new SimpleButtonTag( + array('type' => 'submit', 'name' => 'go', 'value' => 'Go', 'id' => '9')); + $widget->addContent('Go!'); + $form->addWidget($widget); + $this->assertTrue($form->hasSubmit(new SimpleByName('go'))); + $this->assertTrue($form->hasSubmit(new SimpleByLabel('Go!'))); + $this->assertEqual( + $form->submitButton(new SimpleByName('go')), + new SimpleGetEncoding(array('go' => 'Go'))); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Go!')), + new SimpleGetEncoding(array('go' => 'Go'))); + $this->assertEqual( + $form->submitButton(new SimpleById(9)), + new SimpleGetEncoding(array('go' => 'Go'))); + } + + function testMultipleFieldsWithSameNameSubmitted() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $input = new SimpleTextTag(array('name' => 'elements[]', 'value' => '1')); + $form->addWidget($input); + $input = new SimpleTextTag(array('name' => 'elements[]', 'value' => '2')); + $form->addWidget($input); + $form->setField(new SimpleByLabelOrName('elements[]'), '3', 1); + $form->setField(new SimpleByLabelOrName('elements[]'), '4', 2); + $submit = $form->submit(); + $requests = $submit->getAll(); + $this->assertEqual(count($requests), 2); + $this->assertIdentical($requests[0], new SimpleEncodedPair('elements[]', '3')); + $this->assertIdentical($requests[1], new SimpleEncodedPair('elements[]', '4')); + } + + function testSingleSelectFieldSubmitted() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $select = new SimpleSelectionTag(array('name' => 'a')); + $select->addTag(new SimpleOptionTag( + array('value' => 'aaa', 'selected' => ''))); + $form->addWidget($select); + $this->assertIdentical( + $form->submit(), + new SimpleGetEncoding(array('a' => 'aaa'))); + } + + function testSingleSelectFieldSubmittedWithPost() { + $form = new SimpleForm(new SimpleFormTag(array('method' => 'post')), $this->page('htp://host')); + $select = new SimpleSelectionTag(array('name' => 'a')); + $select->addTag(new SimpleOptionTag( + array('value' => 'aaa', 'selected' => ''))); + $form->addWidget($select); + $this->assertIdentical( + $form->submit(), + new SimplePostEncoding(array('a' => 'aaa'))); + } + + function testUnchecked() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleCheckboxTag( + array('name' => 'me', 'type' => 'checkbox'))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), false); + $this->assertTrue($form->setField(new SimpleByName('me'), 'on')); + $this->assertEqual($form->getValue(new SimpleByName('me')), 'on'); + $this->assertFalse($form->setField(new SimpleByName('me'), 'other')); + $this->assertEqual($form->getValue(new SimpleByName('me')), 'on'); + } + + function testChecked() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleCheckboxTag( + array('name' => 'me', 'value' => 'a', 'type' => 'checkbox', 'checked' => ''))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); + $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); + $this->assertEqual($form->getValue(new SimpleByName('me')), 'a'); + $this->assertTrue($form->setField(new SimpleByName('me'), false)); + $this->assertEqual($form->getValue(new SimpleByName('me')), false); + } + + function testSingleUncheckedRadioButton() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), false); + $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); + $this->assertEqual($form->getValue(new SimpleByName('me')), 'a'); + } + + function testSingleCheckedRadioButton() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'a', 'type' => 'radio', 'checked' => ''))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); + $this->assertFalse($form->setField(new SimpleByName('me'), 'other')); + } + + function testUncheckedRadioButtons() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'b', 'type' => 'radio'))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), false); + $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); + $this->assertTrue($form->setField(new SimpleByName('me'), 'b')); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); + $this->assertFalse($form->setField(new SimpleByName('me'), 'c')); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); + } + + function testCheckedRadioButtons() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'a', 'type' => 'radio'))); + $form->addWidget(new SimpleRadioButtonTag( + array('name' => 'me', 'value' => 'b', 'type' => 'radio', 'checked' => ''))); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b'); + $this->assertTrue($form->setField(new SimpleByName('me'), 'a')); + $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a'); + } + + function testMultipleFieldsWithSameKey() { + $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host')); + $form->addWidget(new SimpleCheckboxTag( + array('name' => 'a', 'type' => 'checkbox', 'value' => 'me'))); + $form->addWidget(new SimpleCheckboxTag( + array('name' => 'a', 'type' => 'checkbox', 'value' => 'you'))); + $this->assertIdentical($form->getValue(new SimpleByName('a')), false); + $this->assertTrue($form->setField(new SimpleByName('a'), 'me')); + $this->assertIdentical($form->getValue(new SimpleByName('a')), 'me'); + } + + function testRemoveGetParamsFromAction() { + Mock::generatePartial('SimplePage', 'MockPartialSimplePage', array('getUrl')); + $page = new MockPartialSimplePage(); + $page->returns('getUrl', new SimpleUrl('htp://host/')); + + # Keep GET params in "action", if the form has no widgets + $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1')), $page); + $this->assertEqual($form->getAction()->asString(), 'htp://host/'); + + $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1')), $page); + $form->addWidget(new SimpleTextTag(array('name' => 'me', 'type' => 'text', 'value' => 'a'))); + $this->assertEqual($form->getAction()->asString(), 'htp://host/'); + + $form = new SimpleForm(new SimpleFormTag(array('action'=>'')), $page); + $this->assertEqual($form->getAction()->asString(), 'htp://host/'); + + $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1', 'method'=>'post')), $page); + $this->assertEqual($form->getAction()->asString(), 'htp://host/?test=1'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/frames_test.php b/application/libraries/simpletest/test/frames_test.php new file mode 100644 index 00000000000..29309700e31 --- /dev/null +++ b/application/libraries/simpletest/test/frames_test.php @@ -0,0 +1,549 @@ +setReturnValue('getTitle', 'This page'); + $frameset = new SimpleFrameset($page); + $this->assertEqual($frameset->getTitle(), 'This page'); + } + + function TestHeadersReadFromFramesetByDefault() { + $page = new MockSimplePage(); + $page->setReturnValue('getHeaders', 'Header: content'); + $page->setReturnValue('getMimeType', 'text/xml'); + $page->setReturnValue('getResponseCode', 401); + $page->setReturnValue('getTransportError', 'Could not parse headers'); + $page->setReturnValue('getAuthentication', 'Basic'); + $page->setReturnValue('getRealm', 'Safe place'); + + $frameset = new SimpleFrameset($page); + + $this->assertIdentical($frameset->getHeaders(), 'Header: content'); + $this->assertIdentical($frameset->getMimeType(), 'text/xml'); + $this->assertIdentical($frameset->getResponseCode(), 401); + $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers'); + $this->assertIdentical($frameset->getAuthentication(), 'Basic'); + $this->assertIdentical($frameset->getRealm(), 'Safe place'); + } + + function testEmptyFramesetHasNoContent() { + $page = new MockSimplePage(); + $page->setReturnValue('getRaw', 'This content'); + $frameset = new SimpleFrameset($page); + $this->assertEqual($frameset->getRaw(), ''); + } + + function testRawContentIsFromOnlyFrame() { + $page = new MockSimplePage(); + $page->expectNever('getRaw'); + + $frame = new MockSimplePage(); + $frame->setReturnValue('getRaw', 'Stuff'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame); + $this->assertEqual($frameset->getRaw(), 'Stuff'); + } + + function testRawContentIsFromAllFrames() { + $page = new MockSimplePage(); + $page->expectNever('getRaw'); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getRaw', 'Stuff1'); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getRaw', 'Stuff2'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); + } + + function testTextContentIsFromOnlyFrame() { + $page = new MockSimplePage(); + $page->expectNever('getText'); + + $frame = new MockSimplePage(); + $frame->setReturnValue('getText', 'Stuff'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame); + $this->assertEqual($frameset->getText(), 'Stuff'); + } + + function testTextContentIsFromAllFrames() { + $page = new MockSimplePage(); + $page->expectNever('getText'); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getText', 'Stuff1'); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getText', 'Stuff2'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + $this->assertEqual($frameset->getText(), 'Stuff1 Stuff2'); + } + + function testFieldFoundIsFirstInFramelist() { + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getField', null); + $frame1->expectOnce('getField', array(new SimpleByName('a'))); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getField', 'A'); + $frame2->expectOnce('getField', array(new SimpleByName('a'))); + + $frame3 = new MockSimplePage(); + $frame3->expectNever('getField'); + + $page = new MockSimplePage(); + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + $frameset->addFrame($frame3); + $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'A'); + } + + function testFrameReplacementByIndex() { + $page = new MockSimplePage(); + $page->expectNever('getRaw'); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getRaw', 'Stuff1'); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getRaw', 'Stuff2'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->setFrame(array(1), $frame2); + $this->assertEqual($frameset->getRaw(), 'Stuff2'); + } + + function testFrameReplacementByName() { + $page = new MockSimplePage(); + $page->expectNever('getRaw'); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getRaw', 'Stuff1'); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getRaw', 'Stuff2'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1, 'a'); + $frameset->setFrame(array('a'), $frame2); + $this->assertEqual($frameset->getRaw(), 'Stuff2'); + } +} + +class TestOfFrameNavigation extends UnitTestCase { + + function testStartsWithoutFrameFocus() { + $page = new MockSimplePage(); + $frameset = new SimpleFrameset($page); + $frameset->addFrame(new MockSimplePage()); + $this->assertFalse($frameset->getFrameFocus()); + } + + function testCanFocusOnSingleFrame() { + $page = new MockSimplePage(); + $page->expectNever('getRaw'); + + $frame = new MockSimplePage(); + $frame->setReturnValue('getFrameFocus', array()); + $frame->setReturnValue('getRaw', 'Stuff'); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame); + + $this->assertFalse($frameset->setFrameFocusByIndex(0)); + $this->assertTrue($frameset->setFrameFocusByIndex(1)); + $this->assertEqual($frameset->getRaw(), 'Stuff'); + $this->assertFalse($frameset->setFrameFocusByIndex(2)); + $this->assertIdentical($frameset->getFrameFocus(), array(1)); + } + + function testContentComesFromFrameInFocus() { + $page = new MockSimplePage(); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getRaw', 'Stuff1'); + $frame1->setReturnValue('getFrameFocus', array()); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getRaw', 'Stuff2'); + $frame2->setReturnValue('getFrameFocus', array()); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + + $this->assertTrue($frameset->setFrameFocusByIndex(1)); + $this->assertEqual($frameset->getFrameFocus(), array(1)); + $this->assertEqual($frameset->getRaw(), 'Stuff1'); + + $this->assertTrue($frameset->setFrameFocusByIndex(2)); + $this->assertEqual($frameset->getFrameFocus(), array(2)); + $this->assertEqual($frameset->getRaw(), 'Stuff2'); + + $this->assertFalse($frameset->setFrameFocusByIndex(3)); + $this->assertEqual($frameset->getFrameFocus(), array(2)); + + $frameset->clearFrameFocus(); + $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); + } + + function testCanFocusByName() { + $page = new MockSimplePage(); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getRaw', 'Stuff1'); + $frame1->setReturnValue('getFrameFocus', array()); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getRaw', 'Stuff2'); + $frame2->setReturnValue('getFrameFocus', array()); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1, 'A'); + $frameset->addFrame($frame2, 'B'); + + $this->assertTrue($frameset->setFrameFocus('A')); + $this->assertEqual($frameset->getFrameFocus(), array('A')); + $this->assertEqual($frameset->getRaw(), 'Stuff1'); + + $this->assertTrue($frameset->setFrameFocusByIndex(2)); + $this->assertEqual($frameset->getFrameFocus(), array('B')); + $this->assertEqual($frameset->getRaw(), 'Stuff2'); + + $this->assertFalse($frameset->setFrameFocus('z')); + + $frameset->clearFrameFocus(); + $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2'); + } +} + +class TestOfFramesetPageInterface extends UnitTestCase { + private $page_interface; + private $frameset_interface; + + function __construct() { + parent::__construct(); + $this->page_interface = $this->getPageMethods(); + $this->frameset_interface = $this->getFramesetMethods(); + } + + function assertListInAnyOrder($list, $expected) { + sort($list); + sort($expected); + $this->assertEqual($list, $expected); + } + + private function getPageMethods() { + $methods = array(); + foreach (get_class_methods('SimplePage') as $method) { + if (strtolower($method) == strtolower('SimplePage')) { + continue; + } + if (strtolower($method) == strtolower('getFrameset')) { + continue; + } + if (strncmp($method, '_', 1) == 0) { + continue; + } + if (in_array($method, array('setTitle', 'setBase', 'setForms', 'normalise', 'setFrames', 'addLink'))) { + continue; + } + $methods[] = $method; + } + return $methods; + } + + private function getFramesetMethods() { + $methods = array(); + foreach (get_class_methods('SimpleFrameset') as $method) { + if (strtolower($method) == strtolower('SimpleFrameset')) { + continue; + } + if (strncmp($method, '_', 1) == 0) { + continue; + } + if (strncmp($method, 'add', 3) == 0) { + continue; + } + $methods[] = $method; + } + return $methods; + } + + function testFramsetHasPageInterface() { + $difference = array(); + foreach ($this->page_interface as $method) { + if (! in_array($method, $this->frameset_interface)) { + $this->fail("No [$method] in Frameset class"); + return; + } + } + $this->pass('Frameset covers Page interface'); + } + + function testHeadersReadFromFrameIfInFocus() { + $frame = new MockSimplePage(); + $frame->setReturnValue('getUrl', new SimpleUrl('http://localhost/stuff')); + + $frame->setReturnValue('getRequest', 'POST stuff'); + $frame->setReturnValue('getMethod', 'POST'); + $frame->setReturnValue('getRequestData', array('a' => 'A')); + $frame->setReturnValue('getHeaders', 'Header: content'); + $frame->setReturnValue('getMimeType', 'text/xml'); + $frame->setReturnValue('getResponseCode', 401); + $frame->setReturnValue('getTransportError', 'Could not parse headers'); + $frame->setReturnValue('getAuthentication', 'Basic'); + $frame->setReturnValue('getRealm', 'Safe place'); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame); + $frameset->setFrameFocusByIndex(1); + + $url = new SimpleUrl('http://localhost/stuff'); + $url->setTarget(1); + $this->assertIdentical($frameset->getUrl(), $url); + + $this->assertIdentical($frameset->getRequest(), 'POST stuff'); + $this->assertIdentical($frameset->getMethod(), 'POST'); + $this->assertIdentical($frameset->getRequestData(), array('a' => 'A')); + $this->assertIdentical($frameset->getHeaders(), 'Header: content'); + $this->assertIdentical($frameset->getMimeType(), 'text/xml'); + $this->assertIdentical($frameset->getResponseCode(), 401); + $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers'); + $this->assertIdentical($frameset->getAuthentication(), 'Basic'); + $this->assertIdentical($frameset->getRealm(), 'Safe place'); + } + + function testUrlsComeFromBothFrames() { + $page = new MockSimplePage(); + $page->expectNever('getUrls'); + + $frame1 = new MockSimplePage(); + $frame1->setReturnValue( + 'getUrls', + array('http://www.lastcraft.com/', 'http://myserver/')); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue( + 'getUrls', + array('http://www.lastcraft.com/', 'http://test/')); + + $frameset = new SimpleFrameset($page); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + $this->assertListInAnyOrder( + $frameset->getUrls(), + array('http://www.lastcraft.com/', 'http://myserver/', 'http://test/')); + } + + function testLabelledUrlsComeFromBothFrames() { + $frame1 = new MockSimplePage(); + $frame1->setReturnValue( + 'getUrlsByLabel', + array(new SimpleUrl('goodbye.php')), + array('a')); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue( + 'getUrlsByLabel', + array(new SimpleUrl('hello.php')), + array('a')); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2, 'Two'); + + $expected1 = new SimpleUrl('goodbye.php'); + $expected1->setTarget(1); + $expected2 = new SimpleUrl('hello.php'); + $expected2->setTarget('Two'); + $this->assertEqual( + $frameset->getUrlsByLabel('a'), + array($expected1, $expected2)); + } + + function testUrlByIdComesFromFirstFrameToRespond() { + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getUrlById', new SimpleUrl('four.php'), array(4)); + $frame1->setReturnValue('getUrlById', false, array(5)); + + $frame2 = new MockSimplePage(); + $frame2->setReturnValue('getUrlById', false, array(4)); + $frame2->setReturnValue('getUrlById', new SimpleUrl('five.php'), array(5)); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1); + $frameset->addFrame($frame2); + + $four = new SimpleUrl('four.php'); + $four->setTarget(1); + $this->assertEqual($frameset->getUrlById(4), $four); + $five = new SimpleUrl('five.php'); + $five->setTarget(2); + $this->assertEqual($frameset->getUrlById(5), $five); + } + + function testReadUrlsFromFrameInFocus() { + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getUrls', array('a')); + $frame1->setReturnValue('getUrlsByLabel', array(new SimpleUrl('l'))); + $frame1->setReturnValue('getUrlById', new SimpleUrl('i')); + + $frame2 = new MockSimplePage(); + $frame2->expectNever('getUrls'); + $frame2->expectNever('getUrlsByLabel'); + $frame2->expectNever('getUrlById'); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1, 'A'); + $frameset->addFrame($frame2, 'B'); + $frameset->setFrameFocus('A'); + + $this->assertIdentical($frameset->getUrls(), array('a')); + $expected = new SimpleUrl('l'); + $expected->setTarget('A'); + $this->assertIdentical($frameset->getUrlsByLabel('label'), array($expected)); + $expected = new SimpleUrl('i'); + $expected->setTarget('A'); + $this->assertIdentical($frameset->getUrlById(99), $expected); + } + + function testReadFrameTaggedUrlsFromFrameInFocus() { + $frame = new MockSimplePage(); + + $by_label = new SimpleUrl('l'); + $by_label->setTarget('L'); + $frame->setReturnValue('getUrlsByLabel', array($by_label)); + + $by_id = new SimpleUrl('i'); + $by_id->setTarget('I'); + $frame->setReturnValue('getUrlById', $by_id); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame, 'A'); + $frameset->setFrameFocus('A'); + + $this->assertIdentical($frameset->getUrlsByLabel('label'), array($by_label)); + $this->assertIdentical($frameset->getUrlById(99), $by_id); + } + + function testFindingFormsById() { + $frame = new MockSimplePage(); + $form = new MockSimpleForm(); + $frame->returns('getFormById', $form, array('a')); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame(new MockSimplePage(), 'A'); + $frameset->addFrame($frame, 'B'); + $this->assertSame($frameset->getFormById('a'), $form); + + $frameset->setFrameFocus('A'); + $this->assertNull($frameset->getFormById('a')); + + $frameset->setFrameFocus('B'); + $this->assertSame($frameset->getFormById('a'), $form); + } + + function testFindingFormsBySubmit() { + $frame = new MockSimplePage(); + $form = new MockSimpleForm(); + $frame->returns( + 'getFormBySubmit', + $form, + array(new SimpleByLabel('a'))); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame(new MockSimplePage(), 'A'); + $frameset->addFrame($frame, 'B'); + $this->assertSame($frameset->getFormBySubmit(new SimpleByLabel('a')), $form); + + $frameset->setFrameFocus('A'); + $this->assertNull($frameset->getFormBySubmit(new SimpleByLabel('a'))); + + $frameset->setFrameFocus('B'); + $this->assertSame($frameset->getFormBySubmit(new SimpleByLabel('a')), $form); + } + + function testFindingFormsByImage() { + $frame = new MockSimplePage(); + $form = new MockSimpleForm(); + $frame->returns( + 'getFormByImage', + $form, + array(new SimpleByLabel('a'))); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame(new MockSimplePage(), 'A'); + $frameset->addFrame($frame, 'B'); + $this->assertSame($frameset->getFormByImage(new SimpleByLabel('a')), $form); + + $frameset->setFrameFocus('A'); + $this->assertNull($frameset->getFormByImage(new SimpleByLabel('a'))); + + $frameset->setFrameFocus('B'); + $this->assertSame($frameset->getFormByImage(new SimpleByLabel('a')), $form); + } + + function testSettingAllFrameFieldsWhenNoFrameFocus() { + $frame1 = new MockSimplePage(); + $frame1->expectOnce('setField', array(new SimpleById(22), 'A')); + + $frame2 = new MockSimplePage(); + $frame2->expectOnce('setField', array(new SimpleById(22), 'A')); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1, 'A'); + $frameset->addFrame($frame2, 'B'); + $frameset->setField(new SimpleById(22), 'A'); + } + + function testOnlySettingFieldFromFocusedFrame() { + $frame1 = new MockSimplePage(); + $frame1->expectOnce('setField', array(new SimpleByLabelOrName('a'), 'A')); + + $frame2 = new MockSimplePage(); + $frame2->expectNever('setField'); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1, 'A'); + $frameset->addFrame($frame2, 'B'); + $frameset->setFrameFocus('A'); + $frameset->setField(new SimpleByLabelOrName('a'), 'A'); + } + + function testOnlyGettingFieldFromFocusedFrame() { + $frame1 = new MockSimplePage(); + $frame1->setReturnValue('getField', 'f', array(new SimpleByName('a'))); + + $frame2 = new MockSimplePage(); + $frame2->expectNever('getField'); + + $frameset = new SimpleFrameset(new MockSimplePage()); + $frameset->addFrame($frame1, 'A'); + $frameset->addFrame($frame2, 'B'); + $frameset->setFrameFocus('A'); + $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'f'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/http_test.php b/application/libraries/simpletest/test/http_test.php new file mode 100644 index 00000000000..bd3fdd0d028 --- /dev/null +++ b/application/libraries/simpletest/test/http_test.php @@ -0,0 +1,492 @@ +expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host/here.html')); + $this->assertSame($route->createConnection('GET', 15), $socket); + } + + function testDefaultPostRequest() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("POST /here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host/here.html')); + + $route->createConnection('POST', 15); + } + + function testDefaultDeleteRequest() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("DELETE /here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host/here.html')); + $this->assertSame($route->createConnection('DELETE', 15), $socket); + } + + function testDefaultHeadRequest() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("HEAD /here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host/here.html')); + $this->assertSame($route->createConnection('HEAD', 15), $socket); + } + + function testGetWithPort() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host:81\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host:81/here.html')); + + $route->createConnection('GET', 15); + } + + function testGetWithParameters() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET /here.html?a=1&b=2 HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct(new SimpleUrl('http://a.valid.host/here.html?a=1&b=2')); + + $route->createConnection('GET', 15); + } +} + +class TestOfProxyRoute extends UnitTestCase { + + function testDefaultGet() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleProxyRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct( + new SimpleUrl('http://a.valid.host/here.html'), + new SimpleUrl('http://my-proxy')); + $route->createConnection('GET', 15); + } + + function testDefaultPost() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("POST http://a.valid.host/here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleProxyRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct( + new SimpleUrl('http://a.valid.host/here.html'), + new SimpleUrl('http://my-proxy')); + $route->createConnection('POST', 15); + } + + function testGetWithPort() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET http://a.valid.host:81/here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: my-proxy:8081\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleProxyRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct( + new SimpleUrl('http://a.valid.host:81/here.html'), + new SimpleUrl('http://my-proxy:8081')); + $route->createConnection('GET', 15); + } + + function testGetWithParameters() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html?a=1&b=2 HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n")); + $socket->expectAt(2, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 3); + + $route = new PartialSimpleProxyRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct( + new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'), + new SimpleUrl('http://my-proxy')); + $route->createConnection('GET', 15); + } + + function testGetWithAuthentication() { + $encoded = base64_encode('Me:Secret'); + + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n")); + $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n")); + $socket->expectAt(2, 'write', array("Proxy-Authorization: Basic $encoded\r\n")); + $socket->expectAt(3, 'write', array("Connection: close\r\n")); + $socket->expectCallCount('write', 4); + + $route = new PartialSimpleProxyRoute(); + $route->setReturnReference('createSocket', $socket); + $route->__construct( + new SimpleUrl('http://a.valid.host/here.html'), + new SimpleUrl('http://my-proxy'), + 'Me', + 'Secret'); + $route->createConnection('GET', 15); + } +} + +class TestOfHttpRequest extends UnitTestCase { + + function testReadingBadConnection() { + $socket = new MockSimpleSocket(); + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $request = new SimpleHttpRequest($route, new SimpleGetEncoding()); + $reponse = $request->fetch(15); + $this->assertTrue($reponse->isError()); + } + + function testReadingGoodConnection() { + $socket = new MockSimpleSocket(); + $socket->expectOnce('write', array("\r\n")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('GET', 15)); + + $request = new SimpleHttpRequest($route, new SimpleGetEncoding()); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } + + function testWritingAdditionalHeaders() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("My: stuff\r\n")); + $socket->expectAt(1, 'write', array("\r\n")); + $socket->expectCallCount('write', 2); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + + $request = new SimpleHttpRequest($route, new SimpleGetEncoding()); + $request->addHeaderLine('My: stuff'); + $request->fetch(15); + } + + function testCookieWriting() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Cookie: a=A\r\n")); + $socket->expectAt(1, 'write', array("\r\n")); + $socket->expectCallCount('write', 2); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A'); + + $request = new SimpleHttpRequest($route, new SimpleGetEncoding()); + $request->readCookiesFromJar($jar, new SimpleUrl('/')); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } + + function testMultipleCookieWriting() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Cookie: a=A;b=B\r\n")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A'); + $jar->setCookie('b', 'B'); + + $request = new SimpleHttpRequest($route, new SimpleGetEncoding()); + $request->readCookiesFromJar($jar, new SimpleUrl('/')); + $request->fetch(15); + } + + function testReadingDeleteConnection() { + $socket = new MockSimpleSocket(); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('DELETE', 15)); + + $request = new SimpleHttpRequest($route, new SimpleDeleteEncoding()); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } +} + +class TestOfHttpPostRequest extends UnitTestCase { + + function testReadingBadConnectionCausesErrorBecauseOfDeadSocket() { + $socket = new MockSimpleSocket(); + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $request = new SimpleHttpRequest($route, new SimplePostEncoding()); + $reponse = $request->fetch(15); + $this->assertTrue($reponse->isError()); + } + + function testReadingGoodConnection() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 0\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); + $socket->expectAt(2, 'write', array("\r\n")); + $socket->expectAt(3, 'write', array("")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('POST', 15)); + + $request = new SimpleHttpRequest($route, new SimplePostEncoding()); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } + + function testContentHeadersCalculatedWithUrlEncodedParams() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 3\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n")); + $socket->expectAt(2, 'write', array("\r\n")); + $socket->expectAt(3, 'write', array("a=A")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('POST', 15)); + + $request = new SimpleHttpRequest( + $route, + new SimplePostEncoding(array('a' => 'A'))); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } + + function testContentHeadersCalculatedWithRawEntityBody() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 8\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: text/plain\r\n")); + $socket->expectAt(2, 'write', array("\r\n")); + $socket->expectAt(3, 'write', array("raw body")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('POST', 15)); + + $request = new SimpleHttpRequest( + $route, + new SimplePostEncoding('raw body')); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } + + function testContentHeadersCalculatedWithXmlEntityBody() { + $socket = new MockSimpleSocket(); + $socket->expectAt(0, 'write', array("Content-Length: 27\r\n")); + $socket->expectAt(1, 'write', array("Content-Type: text/xml\r\n")); + $socket->expectAt(2, 'write', array("\r\n")); + $socket->expectAt(3, 'write', array("onetwo")); + + $route = new MockSimpleRoute(); + $route->setReturnReference('createConnection', $socket); + $route->expect('createConnection', array('POST', 15)); + + $request = new SimpleHttpRequest( + $route, + new SimplePostEncoding('onetwo', 'text/xml')); + $this->assertIsA($request->fetch(15), 'SimpleHttpResponse'); + } +} + +class TestOfHttpHeaders extends UnitTestCase { + + function testParseBasicHeaders() { + $headers = new SimpleHttpHeaders( + "HTTP/1.1 200 OK\r\n" . + "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" . + "Content-Type: text/plain\r\n" . + "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" . + "Connection: close"); + $this->assertIdentical($headers->getHttpVersion(), "1.1"); + $this->assertIdentical($headers->getResponseCode(), 200); + $this->assertEqual($headers->getMimeType(), "text/plain"); + } + + function testNonStandardResponseHeader() { + $headers = new SimpleHttpHeaders( + "HTTP/1.1 302 (HTTP-Version SP Status-Code CRLF)\r\n" . + "Connection: close"); + $this->assertIdentical($headers->getResponseCode(), 302); + } + + function testCanParseMultipleCookies() { + $jar = new MockSimpleCookieJar(); + $jar->expectAt(0, 'setCookie', array('a', 'aaa', 'host', '/here/', 'Wed, 25 Dec 2002 04:24:20 GMT')); + $jar->expectAt(1, 'setCookie', array('b', 'bbb', 'host', '/', false)); + + $headers = new SimpleHttpHeaders( + "HTTP/1.1 200 OK\r\n" . + "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" . + "Content-Type: text/plain\r\n" . + "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" . + "Set-Cookie: a=aaa; expires=Wed, 25-Dec-02 04:24:20 GMT; path=/here/\r\n" . + "Set-Cookie: b=bbb\r\n" . + "Connection: close"); + $headers->writeCookiesToJar($jar, new SimpleUrl('http://host')); + } + + function testCanRecogniseRedirect() { + $headers = new SimpleHttpHeaders("HTTP/1.1 301 OK\r\n" . + "Content-Type: text/plain\r\n" . + "Content-Length: 0\r\n" . + "Location: http://www.somewhere-else.com/\r\n" . + "Connection: close"); + $this->assertIdentical($headers->getResponseCode(), 301); + $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/"); + $this->assertTrue($headers->isRedirect()); + } + + function testCanParseChallenge() { + $headers = new SimpleHttpHeaders("HTTP/1.1 401 Authorization required\r\n" . + "Content-Type: text/plain\r\n" . + "Connection: close\r\n" . + "WWW-Authenticate: Basic realm=\"Somewhere\""); + $this->assertEqual($headers->getAuthentication(), 'Basic'); + $this->assertEqual($headers->getRealm(), 'Somewhere'); + $this->assertTrue($headers->isChallenge()); + } +} + +class TestOfHttpResponse extends UnitTestCase { + + function testBadRequest() { + $socket = new MockSimpleSocket(); + $socket->setReturnValue('getSent', ''); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $this->assertTrue($response->isError()); + $this->assertPattern('/Nothing fetched/', $response->getError()); + $this->assertIdentical($response->getContent(), false); + $this->assertIdentical($response->getSent(), ''); + } + + function testBadSocketDuringResponse() { + $socket = new MockSimpleSocket(); + $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n"); + $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); + $socket->setReturnValue("read", ""); + $socket->setReturnValue('getSent', 'HTTP/1.1 ...'); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $this->assertTrue($response->isError()); + $this->assertEqual($response->getContent(), ''); + $this->assertEqual($response->getSent(), 'HTTP/1.1 ...'); + } + + function testIncompleteHeader() { + $socket = new MockSimpleSocket(); + $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n"); + $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); + $socket->setReturnValueAt(2, "read", "Content-Type: text/plain\r\n"); + $socket->setReturnValue("read", ""); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $this->assertTrue($response->isError()); + $this->assertEqual($response->getContent(), ""); + } + + function testParseOfResponseHeadersWhenChunked() { + $socket = new MockSimpleSocket(); + $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\nDate: Mon, 18 Nov 2002 15:50:29 GMT\r\n"); + $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); + $socket->setReturnValueAt(2, "read", "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\nConne"); + $socket->setReturnValueAt(3, "read", "ction: close\r\n\r\nthis is a test file\n"); + $socket->setReturnValueAt(4, "read", "with two lines in it\n"); + $socket->setReturnValue("read", ""); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $this->assertFalse($response->isError()); + $this->assertEqual( + $response->getContent(), + "this is a test file\nwith two lines in it\n"); + $headers = $response->getHeaders(); + $this->assertIdentical($headers->getHttpVersion(), "1.1"); + $this->assertIdentical($headers->getResponseCode(), 200); + $this->assertEqual($headers->getMimeType(), "text/plain"); + $this->assertFalse($headers->isRedirect()); + $this->assertFalse($headers->getLocation()); + } + + function testRedirect() { + $socket = new MockSimpleSocket(); + $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n"); + $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); + $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com/\r\n"); + $socket->setReturnValueAt(3, "read", "Connection: close\r\n"); + $socket->setReturnValueAt(4, "read", "\r\n"); + $socket->setReturnValue("read", ""); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $headers = $response->getHeaders(); + $this->assertTrue($headers->isRedirect()); + $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/"); + } + + function testRedirectWithPort() { + $socket = new MockSimpleSocket(); + $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n"); + $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n"); + $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com:80/\r\n"); + $socket->setReturnValueAt(3, "read", "Connection: close\r\n"); + $socket->setReturnValueAt(4, "read", "\r\n"); + $socket->setReturnValue("read", ""); + + $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding()); + $headers = $response->getHeaders(); + $this->assertTrue($headers->isRedirect()); + $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com:80/"); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/interfaces_test.php b/application/libraries/simpletest/test/interfaces_test.php new file mode 100644 index 00000000000..ab30fe47ff8 --- /dev/null +++ b/application/libraries/simpletest/test/interfaces_test.php @@ -0,0 +1,137 @@ +=')) { + include(dirname(__FILE__) . '/interfaces_test_php5_1.php'); +} + +interface DummyInterface { + function aMethod(); + function anotherMethod($a); + function &referenceMethod(&$a); +} + +Mock::generate('DummyInterface'); +Mock::generatePartial('DummyInterface', 'PartialDummyInterface', array()); + +class TestOfMockInterfaces extends UnitTestCase { + + function testCanMockAnInterface() { + $mock = new MockDummyInterface(); + $this->assertIsA($mock, 'SimpleMock'); + $this->assertIsA($mock, 'MockDummyInterface'); + $this->assertTrue(method_exists($mock, 'aMethod')); + $this->assertTrue(method_exists($mock, 'anotherMethod')); + $this->assertNull($mock->aMethod()); + } + + function testMockedInterfaceExpectsParameters() { + $mock = new MockDummyInterface(); + $this->expectError(); + $mock->anotherMethod(); + } + + function testCannotPartiallyMockAnInterface() { + $this->assertFalse(class_exists('PartialDummyInterface')); + } +} + +class TestOfSpl extends UnitTestCase { + + function skip() { + $this->skipUnless(function_exists('spl_classes'), 'No SPL module loaded'); + } + + function testCanMockAllSplClasses() { + if (! function_exists('spl_classes')) { + return; + } + foreach(spl_classes() as $class) { + if ($class == 'SplHeap' or $class = 'SplFileObject') { + continue; + } + if (version_compare(PHP_VERSION, '5.1', '<') && + $class == 'CachingIterator' || + $class == 'CachingRecursiveIterator' || + $class == 'FilterIterator' || + $class == 'LimitIterator' || + $class == 'ParentIterator') { + // These iterators require an iterator be passed to them during + // construction in PHP 5.0; there is no way for SimpleTest + // to supply such an iterator, however, so support for it is + // disabled. + continue; + } + $mock_class = "Mock$class"; + Mock::generate($class); + $this->assertIsA(new $mock_class(), $mock_class); + } + } + + function testExtensionOfCommonSplClasses() { + Mock::generate('IteratorImplementation'); + $this->assertIsA( + new IteratorImplementation(), + 'IteratorImplementation'); + Mock::generate('IteratorAggregateImplementation'); + $this->assertIsA( + new IteratorAggregateImplementation(), + 'IteratorAggregateImplementation'); + } +} + +class WithHint { + function hinted(DummyInterface $object) { } +} + +class ImplementsDummy implements DummyInterface { + function aMethod() { } + function anotherMethod($a) { } + function &referenceMethod(&$a) { } + function extraMethod($a = false) { } +} +Mock::generate('ImplementsDummy'); + +class TestOfImplementations extends UnitTestCase { + + function testMockedInterfaceCanPassThroughTypeHint() { + $mock = new MockDummyInterface(); + $hinter = new WithHint(); + $hinter->hinted($mock); + } + + function testImplementedInterfacesAreCarried() { + $mock = new MockImplementsDummy(); + $hinter = new WithHint(); + $hinter->hinted($mock); + } + + function testNoSpuriousWarningsWhenSkippingDefaultedParameter() { + $mock = new MockImplementsDummy(); + $mock->extraMethod(); + } +} + +interface SampleInterfaceWithConstruct { + function __construct($something); +} + +class TestOfInterfaceMocksWithConstruct extends UnitTestCase { + function TODO_testBasicConstructOfAnInterface() { // Fails in PHP 5.3dev + Mock::generate('SampleInterfaceWithConstruct'); + } +} + +interface SampleInterfaceWithClone { + function __clone(); +} + +class TestOfSampleInterfaceWithClone extends UnitTestCase { + function testCanMockWithoutErrors() { + Mock::generate('SampleInterfaceWithClone'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/interfaces_test_php5_1.php b/application/libraries/simpletest/test/interfaces_test_php5_1.php new file mode 100644 index 00000000000..3d154f99539 --- /dev/null +++ b/application/libraries/simpletest/test/interfaces_test_php5_1.php @@ -0,0 +1,14 @@ +assertIsA($mock, 'SampleInterfaceWithHintInSignature'); + } +} + diff --git a/application/libraries/simpletest/test/live_test.php b/application/libraries/simpletest/test/live_test.php new file mode 100644 index 00000000000..3fbb54499d3 --- /dev/null +++ b/application/libraries/simpletest/test/live_test.php @@ -0,0 +1,47 @@ +assertTrue($socket->isError()); + $this->assertPattern( + '/Cannot open \\[bad_url:111\\] with \\[/', + $socket->getError()); + $this->assertFalse($socket->isOpen()); + $this->assertFalse($socket->write('A message')); + } + + function testSocketClosure() { + $socket = new SimpleSocket('www.lastcraft.com', 80, 15, 8); + $this->assertTrue($socket->isOpen()); + $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n")); + $socket->write("Host: www.lastcraft.com\r\n"); + $socket->write("Connection: close\r\n\r\n"); + $this->assertEqual($socket->read(), "HTTP/1.1"); + $socket->close(); + $this->assertIdentical($socket->read(), false); + } + + function testRecordOfSentCharacters() { + $socket = new SimpleSocket('www.lastcraft.com', 80, 15); + $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n")); + $socket->write("Host: www.lastcraft.com\r\n"); + $socket->write("Connection: close\r\n\r\n"); + $socket->close(); + $this->assertEqual($socket->getSent(), + "GET /test/network_confirm.php HTTP/1.0\r\n" . + "Host: www.lastcraft.com\r\n" . + "Connection: close\r\n\r\n"); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/mock_objects_test.php b/application/libraries/simpletest/test/mock_objects_test.php new file mode 100644 index 00000000000..7f3178995a7 --- /dev/null +++ b/application/libraries/simpletest/test/mock_objects_test.php @@ -0,0 +1,985 @@ +assertTrue($expectation->test(33)); + $this->assertTrue($expectation->test(false)); + $this->assertTrue($expectation->test(null)); + } +} + +class TestOfParametersExpectation extends UnitTestCase { + + function testEmptyMatch() { + $expectation = new ParametersExpectation(array()); + $this->assertTrue($expectation->test(array())); + $this->assertFalse($expectation->test(array(33))); + } + + function testSingleMatch() { + $expectation = new ParametersExpectation(array(0)); + $this->assertFalse($expectation->test(array(1))); + $this->assertTrue($expectation->test(array(0))); + } + + function testAnyMatch() { + $expectation = new ParametersExpectation(false); + $this->assertTrue($expectation->test(array())); + $this->assertTrue($expectation->test(array(1, 2))); + } + + function testMissingParameter() { + $expectation = new ParametersExpectation(array(0)); + $this->assertFalse($expectation->test(array())); + } + + function testNullParameter() { + $expectation = new ParametersExpectation(array(null)); + $this->assertTrue($expectation->test(array(null))); + $this->assertFalse($expectation->test(array())); + } + + function testAnythingExpectations() { + $expectation = new ParametersExpectation(array(new AnythingExpectation())); + $this->assertFalse($expectation->test(array())); + $this->assertIdentical($expectation->test(array(null)), true); + $this->assertIdentical($expectation->test(array(13)), true); + } + + function testOtherExpectations() { + $expectation = new ParametersExpectation( + array(new PatternExpectation('/hello/i'))); + $this->assertFalse($expectation->test(array('Goodbye'))); + $this->assertTrue($expectation->test(array('hello'))); + $this->assertTrue($expectation->test(array('Hello'))); + } + + function testIdentityOnly() { + $expectation = new ParametersExpectation(array("0")); + $this->assertFalse($expectation->test(array(0))); + $this->assertTrue($expectation->test(array("0"))); + } + + function testLongList() { + $expectation = new ParametersExpectation( + array("0", 0, new AnythingExpectation(), false)); + $this->assertTrue($expectation->test(array("0", 0, 37, false))); + $this->assertFalse($expectation->test(array("0", 0, 37, true))); + $this->assertFalse($expectation->test(array("0", 0, 37))); + } +} + +class TestOfSimpleSignatureMap extends UnitTestCase { + + function testEmpty() { + $map = new SimpleSignatureMap(); + $this->assertFalse($map->isMatch("any", array())); + $this->assertNull($map->findFirstAction("any", array())); + } + + function testDifferentCallSignaturesCanHaveDifferentReferences() { + $map = new SimpleSignatureMap(); + $fred = 'Fred'; + $jim = 'jim'; + $map->add(array(0), $fred); + $map->add(array('0'), $jim); + $this->assertSame($fred, $map->findFirstAction(array(0))); + $this->assertSame($jim, $map->findFirstAction(array('0'))); + } + + function testWildcard() { + $fred = 'Fred'; + $map = new SimpleSignatureMap(); + $map->add(array(new AnythingExpectation(), 1, 3), $fred); + $this->assertTrue($map->isMatch(array(2, 1, 3))); + $this->assertSame($map->findFirstAction(array(2, 1, 3)), $fred); + } + + function testAllWildcard() { + $fred = 'Fred'; + $map = new SimpleSignatureMap(); + $this->assertFalse($map->isMatch(array(2, 1, 3))); + $map->add('', $fred); + $this->assertTrue($map->isMatch(array(2, 1, 3))); + $this->assertSame($map->findFirstAction(array(2, 1, 3)), $fred); + } + + function testOrdering() { + $map = new SimpleSignatureMap(); + $map->add(array(1, 2), new SimpleByValue("1, 2")); + $map->add(array(1, 3), new SimpleByValue("1, 3")); + $map->add(array(1), new SimpleByValue("1")); + $map->add(array(1, 4), new SimpleByValue("1, 4")); + $map->add(array(new AnythingExpectation()), new SimpleByValue("Any")); + $map->add(array(2), new SimpleByValue("2")); + $map->add("", new SimpleByValue("Default")); + $map->add(array(), new SimpleByValue("None")); + $this->assertEqual($map->findFirstAction(array(1, 2)), new SimpleByValue("1, 2")); + $this->assertEqual($map->findFirstAction(array(1, 3)), new SimpleByValue("1, 3")); + $this->assertEqual($map->findFirstAction(array(1, 4)), new SimpleByValue("1, 4")); + $this->assertEqual($map->findFirstAction(array(1)), new SimpleByValue("1")); + $this->assertEqual($map->findFirstAction(array(2)), new SimpleByValue("Any")); + $this->assertEqual($map->findFirstAction(array(3)), new SimpleByValue("Any")); + $this->assertEqual($map->findFirstAction(array()), new SimpleByValue("Default")); + } +} + +class TestOfCallSchedule extends UnitTestCase { + function testCanBeSetToAlwaysReturnTheSameReference() { + $a = 5; + $schedule = new SimpleCallSchedule(); + $schedule->register('aMethod', false, new SimpleByReference($a)); + $this->assertReference($schedule->respond(0, 'aMethod', array()), $a); + $this->assertReference($schedule->respond(1, 'aMethod', array()), $a); + } + + function testSpecificSignaturesOverrideTheAlwaysCase() { + $any = 'any'; + $one = 'two'; + $schedule = new SimpleCallSchedule(); + $schedule->register('aMethod', array(1), new SimpleByReference($one)); + $schedule->register('aMethod', false, new SimpleByReference($any)); + $this->assertReference($schedule->respond(0, 'aMethod', array(2)), $any); + $this->assertReference($schedule->respond(0, 'aMethod', array(1)), $one); + } + + function testReturnsCanBeSetOverTime() { + $one = 'one'; + $two = 'two'; + $schedule = new SimpleCallSchedule(); + $schedule->registerAt(0, 'aMethod', false, new SimpleByReference($one)); + $schedule->registerAt(1, 'aMethod', false, new SimpleByReference($two)); + $this->assertReference($schedule->respond(0, 'aMethod', array()), $one); + $this->assertReference($schedule->respond(1, 'aMethod', array()), $two); + } + + function testReturnsOverTimecanBeAlteredByTheArguments() { + $one = '1'; + $two = '2'; + $two_a = '2a'; + $schedule = new SimpleCallSchedule(); + $schedule->registerAt(0, 'aMethod', false, new SimpleByReference($one)); + $schedule->registerAt(1, 'aMethod', array('a'), new SimpleByReference($two_a)); + $schedule->registerAt(1, 'aMethod', false, new SimpleByReference($two)); + $this->assertReference($schedule->respond(0, 'aMethod', array()), $one); + $this->assertReference($schedule->respond(1, 'aMethod', array()), $two); + $this->assertReference($schedule->respond(1, 'aMethod', array('a')), $two_a); + } + + function testCanReturnByValue() { + $a = 5; + $schedule = new SimpleCallSchedule(); + $schedule->register('aMethod', false, new SimpleByValue($a)); + $this->assertCopy($schedule->respond(0, 'aMethod', array()), $a); + } + + function testCanThrowException() { + if (version_compare(phpversion(), '5', '>=')) { + $schedule = new SimpleCallSchedule(); + $schedule->register('aMethod', false, new SimpleThrower(new Exception('Ouch'))); + $this->expectException(new Exception('Ouch')); + $schedule->respond(0, 'aMethod', array()); + } + } + + function testCanEmitError() { + $schedule = new SimpleCallSchedule(); + $schedule->register('aMethod', false, new SimpleErrorThrower('Ouch', E_USER_WARNING)); + $this->expectError('Ouch'); + $schedule->respond(0, 'aMethod', array()); + } +} + +class Dummy { + function Dummy() { + } + + function aMethod() { + return true; + } + + function &aReferenceMethod() { + return true; + } + + function anotherMethod() { + return true; + } +} +Mock::generate('Dummy'); +Mock::generate('Dummy', 'AnotherMockDummy'); +Mock::generate('Dummy', 'MockDummyWithExtraMethods', array('extraMethod')); + +class TestOfMockGeneration extends UnitTestCase { + + function testCloning() { + $mock = new MockDummy(); + $this->assertTrue(method_exists($mock, "aMethod")); + $this->assertNull($mock->aMethod()); + } + + function testCloningWithExtraMethod() { + $mock = new MockDummyWithExtraMethods(); + $this->assertTrue(method_exists($mock, "extraMethod")); + } + + function testCloningWithChosenClassName() { + $mock = new AnotherMockDummy(); + $this->assertTrue(method_exists($mock, "aMethod")); + } +} + +class TestOfMockReturns extends UnitTestCase { + + function testDefaultReturn() { + $mock = new MockDummy(); + $mock->returnsByValue("aMethod", "aaa"); + $this->assertIdentical($mock->aMethod(), "aaa"); + $this->assertIdentical($mock->aMethod(), "aaa"); + } + + function testParameteredReturn() { + $mock = new MockDummy(); + $mock->returnsByValue('aMethod', 'aaa', array(1, 2, 3)); + $this->assertNull($mock->aMethod()); + $this->assertIdentical($mock->aMethod(1, 2, 3), 'aaa'); + } + + function testSetReturnGivesObjectReference() { + $mock = new MockDummy(); + $object = new Dummy(); + $mock->returns('aMethod', $object, array(1, 2, 3)); + $this->assertSame($mock->aMethod(1, 2, 3), $object); + } + + function testSetReturnReferenceGivesOriginalReference() { + $mock = new MockDummy(); + $object = 1; + $mock->returnsByReference('aReferenceMethod', $object, array(1, 2, 3)); + $this->assertReference($mock->aReferenceMethod(1, 2, 3), $object); + } + + function testReturnValueCanBeChosenJustByPatternMatchingArguments() { + $mock = new MockDummy(); + $mock->returnsByValue( + "aMethod", + "aaa", + array(new PatternExpectation('/hello/i'))); + $this->assertIdentical($mock->aMethod('Hello'), 'aaa'); + $this->assertNull($mock->aMethod('Goodbye')); + } + + function testMultipleMethods() { + $mock = new MockDummy(); + $mock->returnsByValue("aMethod", 100, array(1)); + $mock->returnsByValue("aMethod", 200, array(2)); + $mock->returnsByValue("anotherMethod", 10, array(1)); + $mock->returnsByValue("anotherMethod", 20, array(2)); + $this->assertIdentical($mock->aMethod(1), 100); + $this->assertIdentical($mock->anotherMethod(1), 10); + $this->assertIdentical($mock->aMethod(2), 200); + $this->assertIdentical($mock->anotherMethod(2), 20); + } + + function testReturnSequence() { + $mock = new MockDummy(); + $mock->returnsByValueAt(0, "aMethod", "aaa"); + $mock->returnsByValueAt(1, "aMethod", "bbb"); + $mock->returnsByValueAt(3, "aMethod", "ddd"); + $this->assertIdentical($mock->aMethod(), "aaa"); + $this->assertIdentical($mock->aMethod(), "bbb"); + $this->assertNull($mock->aMethod()); + $this->assertIdentical($mock->aMethod(), "ddd"); + } + + function testSetReturnReferenceAtGivesOriginal() { + $mock = new MockDummy(); + $object = 100; + $mock->returnsByReferenceAt(1, "aReferenceMethod", $object); + $this->assertNull($mock->aReferenceMethod()); + $this->assertReference($mock->aReferenceMethod(), $object); + $this->assertNull($mock->aReferenceMethod()); + } + + function testReturnsAtGivesOriginalObjectHandle() { + $mock = new MockDummy(); + $object = new Dummy(); + $mock->returnsAt(1, "aMethod", $object); + $this->assertNull($mock->aMethod()); + $this->assertSame($mock->aMethod(), $object); + $this->assertNull($mock->aMethod()); + } + + function testComplicatedReturnSequence() { + $mock = new MockDummy(); + $object = new Dummy(); + $mock->returnsAt(1, "aMethod", "aaa", array("a")); + $mock->returnsAt(1, "aMethod", "bbb"); + $mock->returnsAt(2, "aMethod", $object, array('*', 2)); + $mock->returnsAt(2, "aMethod", "value", array('*', 3)); + $mock->returns("aMethod", 3, array(3)); + $this->assertNull($mock->aMethod()); + $this->assertEqual($mock->aMethod("a"), "aaa"); + $this->assertSame($mock->aMethod(1, 2), $object); + $this->assertEqual($mock->aMethod(3), 3); + $this->assertNull($mock->aMethod()); + } + + function testMultipleMethodSequences() { + $mock = new MockDummy(); + $mock->returnsByValueAt(0, "aMethod", "aaa"); + $mock->returnsByValueAt(1, "aMethod", "bbb"); + $mock->returnsByValueAt(0, "anotherMethod", "ccc"); + $mock->returnsByValueAt(1, "anotherMethod", "ddd"); + $this->assertIdentical($mock->aMethod(), "aaa"); + $this->assertIdentical($mock->anotherMethod(), "ccc"); + $this->assertIdentical($mock->aMethod(), "bbb"); + $this->assertIdentical($mock->anotherMethod(), "ddd"); + } + + function testSequenceFallback() { + $mock = new MockDummy(); + $mock->returnsByValueAt(0, "aMethod", "aaa", array('a')); + $mock->returnsByValueAt(1, "aMethod", "bbb", array('a')); + $mock->returnsByValue("aMethod", "AAA"); + $this->assertIdentical($mock->aMethod('a'), "aaa"); + $this->assertIdentical($mock->aMethod('b'), "AAA"); + } + + function testMethodInterference() { + $mock = new MockDummy(); + $mock->returnsByValueAt(0, "anotherMethod", "aaa"); + $mock->returnsByValue("aMethod", "AAA"); + $this->assertIdentical($mock->aMethod(), "AAA"); + $this->assertIdentical($mock->anotherMethod(), "aaa"); + } +} + +class TestOfMockExpectationsThatPass extends UnitTestCase { + + function testAnyArgument() { + $mock = new MockDummy(); + $mock->expect('aMethod', array('*')); + $mock->aMethod(1); + $mock->aMethod('hello'); + } + + function testAnyTwoArguments() { + $mock = new MockDummy(); + $mock->expect('aMethod', array('*', '*')); + $mock->aMethod(1, 2); + } + + function testSpecificArgument() { + $mock = new MockDummy(); + $mock->expect('aMethod', array(1)); + $mock->aMethod(1); + } + + function testExpectation() { + $mock = new MockDummy(); + $mock->expect('aMethod', array(new IsAExpectation('Dummy'))); + $mock->aMethod(new Dummy()); + } + + function testArgumentsInSequence() { + $mock = new MockDummy(); + $mock->expectAt(0, 'aMethod', array(1, 2)); + $mock->expectAt(1, 'aMethod', array(3, 4)); + $mock->aMethod(1, 2); + $mock->aMethod(3, 4); + } + + function testAtLeastOnceSatisfiedByOneCall() { + $mock = new MockDummy(); + $mock->expectAtLeastOnce('aMethod'); + $mock->aMethod(); + } + + function testAtLeastOnceSatisfiedByTwoCalls() { + $mock = new MockDummy(); + $mock->expectAtLeastOnce('aMethod'); + $mock->aMethod(); + $mock->aMethod(); + } + + function testOnceSatisfiedByOneCall() { + $mock = new MockDummy(); + $mock->expectOnce('aMethod'); + $mock->aMethod(); + } + + function testMinimumCallsSatisfiedByEnoughCalls() { + $mock = new MockDummy(); + $mock->expectMinimumCallCount('aMethod', 1); + $mock->aMethod(); + } + + function testMinimumCallsSatisfiedByTooManyCalls() { + $mock = new MockDummy(); + $mock->expectMinimumCallCount('aMethod', 3); + $mock->aMethod(); + $mock->aMethod(); + $mock->aMethod(); + $mock->aMethod(); + } + + function testMaximumCallsSatisfiedByEnoughCalls() { + $mock = new MockDummy(); + $mock->expectMaximumCallCount('aMethod', 1); + $mock->aMethod(); + } + + function testMaximumCallsSatisfiedByNoCalls() { + $mock = new MockDummy(); + $mock->expectMaximumCallCount('aMethod', 1); + } +} + +class MockWithInjectedTestCase extends SimpleMock { + protected function getCurrentTestCase() { + return SimpleTest::getContext()->getTest()->getMockedTest(); + } +} +SimpleTest::setMockBaseClass('MockWithInjectedTestCase'); +Mock::generate('Dummy', 'MockDummyWithInjectedTestCase'); +SimpleTest::setMockBaseClass('SimpleMock'); +Mock::generate('SimpleTestCase'); + +class LikeExpectation extends IdenticalExpectation { + function __construct($expectation) { + $expectation->message = ''; + parent::__construct($expectation); + } + + function test($compare) { + $compare->message = ''; + return parent::test($compare); + } + + function testMessage($compare) { + $compare->message = ''; + return parent::testMessage($compare); + } +} + +class TestOfMockExpectations extends UnitTestCase { + private $test; + + function setUp() { + $this->test = new MockSimpleTestCase(); + } + + function getMockedTest() { + return $this->test; + } + + function testSettingExpectationOnNonMethodThrowsError() { + $mock = new MockDummyWithInjectedTestCase(); + $this->expectError(); + $mock->expectMaximumCallCount('aMissingMethod', 2); + } + + function testMaxCallsDetectsOverrun() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 3)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectMaximumCallCount('aMethod', 2); + $mock->aMethod(); + $mock->aMethod(); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testTallyOnMaxCallsSendsPassOnUnderrun() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 2)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectMaximumCallCount("aMethod", 2); + $mock->aMethod(); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testExpectNeverDetectsOverrun() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 1)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectNever('aMethod'); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testTallyOnExpectNeverStillSendsPassOnUnderrun() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 0)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectNever('aMethod'); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testMinCalls() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 2)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectMinimumCallCount('aMethod', 2); + $mock->aMethod(); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testFailedNever() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 1)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectNever('aMethod'); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testUnderOnce() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 0)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectOnce('aMethod'); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testOverOnce() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 2)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectOnce('aMethod'); + $mock->aMethod(); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testUnderAtLeastOnce() { + $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 0)); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectAtLeastOnce("aMethod"); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testZeroArguments() { + $this->test->expectOnce('assert', + array(new MemberExpectation('expected', array()), array(), '*')); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expect('aMethod', array()); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testExpectedArguments() { + $this->test->expectOnce('assert', + array(new MemberExpectation('expected', array(1, 2, 3)), array(1, 2, 3), '*')); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expect('aMethod', array(1, 2, 3)); + $mock->aMethod(1, 2, 3); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testFailedArguments() { + $this->test->expectOnce('assert', + array(new MemberExpectation('expected', array('this')), array('that'), '*')); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expect('aMethod', array('this')); + $mock->aMethod('that'); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testWildcardsAreTranslatedToAnythingExpectations() { + $this->test->expectOnce('assert', + array(new MemberExpectation('expected', + array(new AnythingExpectation(), + 123, + new AnythingExpectation())), + array(100, 123, 101), '*')); + $mock = new MockDummyWithInjectedTestCase($this); + $mock->expect("aMethod", array('*', 123, '*')); + $mock->aMethod(100, 123, 101); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testSpecificPassingSequence() { + $this->test->expectAt(0, 'assert', + array(new MemberExpectation('expected', array(1, 2, 3)), array(1, 2, 3), '*')); + $this->test->expectAt(1, 'assert', + array(new MemberExpectation('expected', array('Hello')), array('Hello'), '*')); + $mock = new MockDummyWithInjectedTestCase(); + $mock->expectAt(1, 'aMethod', array(1, 2, 3)); + $mock->expectAt(2, 'aMethod', array('Hello')); + $mock->aMethod(); + $mock->aMethod(1, 2, 3); + $mock->aMethod('Hello'); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } + + function testNonArrayForExpectedParametersGivesError() { + $mock = new MockDummyWithInjectedTestCase(); + $this->expectError(new PatternExpectation('/\$args.*not an array/i')); + $mock->expect("aMethod", "foo"); + $mock->aMethod(); + $mock->mock->atTestEnd('testSomething', $this->test); + } +} + +class TestOfMockComparisons extends UnitTestCase { + + function testEqualComparisonOfMocksDoesNotCrash() { + $expectation = new EqualExpectation(new MockDummy()); + $this->assertTrue($expectation->test(new MockDummy(), true)); + } + + function testIdenticalComparisonOfMocksDoesNotCrash() { + $expectation = new IdenticalExpectation(new MockDummy()); + $this->assertTrue($expectation->test(new MockDummy())); + } +} + +class ClassWithSpecialMethods { + function __get($name) { } + function __set($name, $value) { } + function __isset($name) { } + function __unset($name) { } + function __call($method, $arguments) { } + function __toString() { } +} +Mock::generate('ClassWithSpecialMethods'); + +class TestOfSpecialMethodsAfterPHP51 extends UnitTestCase { + + function skip() { + $this->skipIf(version_compare(phpversion(), '5.1', '<'), '__isset and __unset overloading not tested unless PHP 5.1+'); + } + + function testCanEmulateIsset() { + $mock = new MockClassWithSpecialMethods(); + $mock->returnsByValue('__isset', true); + $this->assertIdentical(isset($mock->a), true); + } + + function testCanExpectUnset() { + $mock = new MockClassWithSpecialMethods(); + $mock->expectOnce('__unset', array('a')); + unset($mock->a); + } + +} + +class TestOfSpecialMethods extends UnitTestCase { + function skip() { + $this->skipIf(version_compare(phpversion(), '5', '<'), 'Overloading not tested unless PHP 5+'); + } + + function testCanMockTheThingAtAll() { + $mock = new MockClassWithSpecialMethods(); + } + + function testReturnFromSpecialAccessor() { + $mock = new MockClassWithSpecialMethods(); + $mock->returnsByValue('__get', '1st Return', array('first')); + $mock->returnsByValue('__get', '2nd Return', array('second')); + $this->assertEqual($mock->first, '1st Return'); + $this->assertEqual($mock->second, '2nd Return'); + } + + function testcanExpectTheSettingOfValue() { + $mock = new MockClassWithSpecialMethods(); + $mock->expectOnce('__set', array('a', 'A')); + $mock->a = 'A'; + } + + function testCanSimulateAnOverloadmethod() { + $mock = new MockClassWithSpecialMethods(); + $mock->expectOnce('__call', array('amOverloaded', array('A'))); + $mock->returnsByValue('__call', 'aaa'); + $this->assertIdentical($mock->amOverloaded('A'), 'aaa'); + } + + function testToStringMagic() { + $mock = new MockClassWithSpecialMethods(); + $mock->expectOnce('__toString'); + $mock->returnsByValue('__toString', 'AAA'); + ob_start(); + print $mock; + $output = ob_get_contents(); + ob_end_clean(); + $this->assertEqual($output, 'AAA'); + } +} + +class WithStaticMethod { + static function aStaticMethod() { } +} +Mock::generate('WithStaticMethod'); + +class TestOfMockingClassesWithStaticMethods extends UnitTestCase { + + function testStaticMethodIsMockedAsStatic() { + $mock = new WithStaticMethod(); + $reflection = new ReflectionClass($mock); + $method = $reflection->getMethod('aStaticMethod'); + $this->assertTrue($method->isStatic()); + } +} + +class MockTestException extends Exception { } + +class TestOfThrowingExceptionsFromMocks extends UnitTestCase { + + function testCanThrowOnMethodCall() { + $mock = new MockDummy(); + $mock->throwOn('aMethod'); + $this->expectException(); + $mock->aMethod(); + } + + function testCanThrowSpecificExceptionOnMethodCall() { + $mock = new MockDummy(); + $mock->throwOn('aMethod', new MockTestException()); + $this->expectException(); + $mock->aMethod(); + } + + function testThrowsOnlyWhenCallSignatureMatches() { + $mock = new MockDummy(); + $mock->throwOn('aMethod', new MockTestException(), array(3)); + $mock->aMethod(1); + $mock->aMethod(2); + $this->expectException(); + $mock->aMethod(3); + } + + function testCanThrowOnParticularInvocation() { + $mock = new MockDummy(); + $mock->throwAt(2, 'aMethod', new MockTestException()); + $mock->aMethod(); + $mock->aMethod(); + $this->expectException(); + $mock->aMethod(); + } +} + +class TestOfThrowingErrorsFromMocks extends UnitTestCase { + + function testCanGenerateErrorFromMethodCall() { + $mock = new MockDummy(); + $mock->errorOn('aMethod', 'Ouch!'); + $this->expectError('Ouch!'); + $mock->aMethod(); + } + + function testGeneratesErrorOnlyWhenCallSignatureMatches() { + $mock = new MockDummy(); + $mock->errorOn('aMethod', 'Ouch!', array(3)); + $mock->aMethod(1); + $mock->aMethod(2); + $this->expectError(); + $mock->aMethod(3); + } + + function testCanGenerateErrorOnParticularInvocation() { + $mock = new MockDummy(); + $mock->errorAt(2, 'aMethod', 'Ouch!'); + $mock->aMethod(); + $mock->aMethod(); + $this->expectError(); + $mock->aMethod(); + } +} + +Mock::generatePartial('Dummy', 'TestDummy', array('anotherMethod', 'aReferenceMethod')); + +class TestOfPartialMocks extends UnitTestCase { + + function testMethodReplacementWithNoBehaviourReturnsNull() { + $mock = new TestDummy(); + $this->assertEqual($mock->aMethod(99), 99); + $this->assertNull($mock->anotherMethod()); + } + + function testSettingReturns() { + $mock = new TestDummy(); + $mock->returnsByValue('anotherMethod', 33, array(3)); + $mock->returnsByValue('anotherMethod', 22); + $mock->returnsByValueAt(2, 'anotherMethod', 44, array(3)); + $this->assertEqual($mock->anotherMethod(), 22); + $this->assertEqual($mock->anotherMethod(3), 33); + $this->assertEqual($mock->anotherMethod(3), 44); + } + + function testSetReturnReferenceGivesOriginal() { + $mock = new TestDummy(); + $object = 99; + $mock->returnsByReferenceAt(0, 'aReferenceMethod', $object, array(3)); + $this->assertReference($mock->aReferenceMethod(3), $object); + } + + function testReturnsAtGivesOriginalObjectHandle() { + $mock = new TestDummy(); + $object = new Dummy(); + $mock->returnsAt(0, 'anotherMethod', $object, array(3)); + $this->assertSame($mock->anotherMethod(3), $object); + } + + function testExpectations() { + $mock = new TestDummy(); + $mock->expectCallCount('anotherMethod', 2); + $mock->expect('anotherMethod', array(77)); + $mock->expectAt(1, 'anotherMethod', array(66)); + $mock->anotherMethod(77); + $mock->anotherMethod(66); + } + + function testSettingExpectationOnMissingMethodThrowsError() { + $mock = new TestDummy(); + $this->expectError(); + $mock->expectCallCount('aMissingMethod', 2); + } +} + +class ConstructorSuperClass { + function ConstructorSuperClass() { } +} + +class ConstructorSubClass extends ConstructorSuperClass { } + +class TestOfPHP4StyleSuperClassConstruct extends UnitTestCase { + function testBasicConstruct() { + Mock::generate('ConstructorSubClass'); + $mock = new MockConstructorSubClass(); + $this->assertIsA($mock, 'ConstructorSubClass'); + $this->assertTrue(method_exists($mock, 'ConstructorSuperClass')); + } +} + +class TestOfPHP5StaticMethodMocking extends UnitTestCase { + function testCanCreateAMockObjectWithStaticMethodsWithoutError() { + eval(' + class SimpleObjectContainingStaticMethod { + static function someStatic() { } + } + '); + Mock::generate('SimpleObjectContainingStaticMethod'); + } +} + +class TestOfPHP5AbstractMethodMocking extends UnitTestCase { + function testCanCreateAMockObjectFromAnAbstractWithProperFunctionDeclarations() { + eval(' + abstract class SimpleAbstractClassContainingAbstractMethods { + abstract function anAbstract(); + abstract function anAbstractWithParameter($foo); + abstract function anAbstractWithMultipleParameters($foo, $bar); + } + '); + Mock::generate('SimpleAbstractClassContainingAbstractMethods'); + $this->assertTrue( + method_exists( + // Testing with class name alone does not work in PHP 5.0 + new MockSimpleAbstractClassContainingAbstractMethods, + 'anAbstract' + ) + ); + $this->assertTrue( + method_exists( + new MockSimpleAbstractClassContainingAbstractMethods, + 'anAbstractWithParameter' + ) + ); + $this->assertTrue( + method_exists( + new MockSimpleAbstractClassContainingAbstractMethods, + 'anAbstractWithMultipleParameters' + ) + ); + } + + function testMethodsDefinedAsAbstractInParentShouldHaveFullSignature() { + eval(' + abstract class SimpleParentAbstractClassContainingAbstractMethods { + abstract function anAbstract(); + abstract function anAbstractWithParameter($foo); + abstract function anAbstractWithMultipleParameters($foo, $bar); + } + + class SimpleChildAbstractClassContainingAbstractMethods extends SimpleParentAbstractClassContainingAbstractMethods { + function anAbstract(){} + function anAbstractWithParameter($foo){} + function anAbstractWithMultipleParameters($foo, $bar){} + } + + class EvenDeeperEmptyChildClass extends SimpleChildAbstractClassContainingAbstractMethods {} + '); + Mock::generate('SimpleChildAbstractClassContainingAbstractMethods'); + $this->assertTrue( + method_exists( + new MockSimpleChildAbstractClassContainingAbstractMethods, + 'anAbstract' + ) + ); + $this->assertTrue( + method_exists( + new MockSimpleChildAbstractClassContainingAbstractMethods, + 'anAbstractWithParameter' + ) + ); + $this->assertTrue( + method_exists( + new MockSimpleChildAbstractClassContainingAbstractMethods, + 'anAbstractWithMultipleParameters' + ) + ); + Mock::generate('EvenDeeperEmptyChildClass'); + $this->assertTrue( + method_exists( + new MockEvenDeeperEmptyChildClass, + 'anAbstract' + ) + ); + $this->assertTrue( + method_exists( + new MockEvenDeeperEmptyChildClass, + 'anAbstractWithParameter' + ) + ); + $this->assertTrue( + method_exists( + new MockEvenDeeperEmptyChildClass, + 'anAbstractWithMultipleParameters' + ) + ); + } +} + +class DummyWithProtected +{ + public function aMethodCallsProtected() { return $this->aProtectedMethod(); } + protected function aProtectedMethod() { return true; } +} + +Mock::generatePartial('DummyWithProtected', 'TestDummyWithProtected', array('aProtectedMethod')); +class TestOfProtectedMethodPartialMocks extends UnitTestCase +{ + function testProtectedMethodExists() { + $this->assertTrue( + method_exists( + new TestDummyWithProtected, + 'aProtectedMethod' + ) + ); + } + + function testProtectedMethodIsCalled() { + $object = new DummyWithProtected(); + $this->assertTrue($object->aMethodCallsProtected(), 'ensure original was called'); + } + + function testMockedMethodIsCalled() { + $object = new TestDummyWithProtected(); + $object->returnsByValue('aProtectedMethod', false); + $this->assertFalse($object->aMethodCallsProtected()); + } +} + +?> diff --git a/application/libraries/simpletest/test/page_test.php b/application/libraries/simpletest/test/page_test.php new file mode 100644 index 00000000000..fdc15c5d008 --- /dev/null +++ b/application/libraries/simpletest/test/page_test.php @@ -0,0 +1,166 @@ +assertEqual($page->getTransportError(), 'No page fetched yet'); + $this->assertIdentical($page->getRaw(), false); + $this->assertIdentical($page->getHeaders(), false); + $this->assertIdentical($page->getMimeType(), false); + $this->assertIdentical($page->getResponseCode(), false); + $this->assertIdentical($page->getAuthentication(), false); + $this->assertIdentical($page->getRealm(), false); + $this->assertFalse($page->hasFrames()); + $this->assertIdentical($page->getUrls(), array()); + $this->assertIdentical($page->getTitle(), false); + } +} + +class TestOfPageHeaders extends UnitTestCase { + + function testUrlAccessor() { + $headers = new MockSimpleHttpHeaders(); + + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getHeaders', $headers); + $response->setReturnValue('getMethod', 'POST'); + $response->setReturnValue('getUrl', new SimpleUrl('here')); + $response->setReturnValue('getRequestData', array('a' => 'A')); + + $page = new SimplePage($response); + $this->assertEqual($page->getMethod(), 'POST'); + $this->assertEqual($page->getUrl(), new SimpleUrl('here')); + $this->assertEqual($page->getRequestData(), array('a' => 'A')); + } + + function testTransportError() { + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getError', 'Ouch'); + + $page = new SimplePage($response); + $this->assertEqual($page->getTransportError(), 'Ouch'); + } + + function testHeadersAccessor() { + $headers = new MockSimpleHttpHeaders(); + $headers->setReturnValue('getRaw', 'My: Headers'); + + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getHeaders', $headers); + + $page = new SimplePage($response); + $this->assertEqual($page->getHeaders(), 'My: Headers'); + } + + function testMimeAccessor() { + $headers = new MockSimpleHttpHeaders(); + $headers->setReturnValue('getMimeType', 'text/html'); + + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getHeaders', $headers); + + $page = new SimplePage($response); + $this->assertEqual($page->getMimeType(), 'text/html'); + } + + function testResponseAccessor() { + $headers = new MockSimpleHttpHeaders(); + $headers->setReturnValue('getResponseCode', 301); + + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getHeaders', $headers); + + $page = new SimplePage($response); + $this->assertIdentical($page->getResponseCode(), 301); + } + + function testAuthenticationAccessors() { + $headers = new MockSimpleHttpHeaders(); + $headers->setReturnValue('getAuthentication', 'Basic'); + $headers->setReturnValue('getRealm', 'Secret stuff'); + + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getHeaders', $headers); + + $page = new SimplePage($response); + $this->assertEqual($page->getAuthentication(), 'Basic'); + $this->assertEqual($page->getRealm(), 'Secret stuff'); + } +} + +class TestOfHtmlStrippingAndNormalisation extends UnitTestCase { + + function testImageSuppressionWhileKeepingParagraphsAndAltText() { + $this->assertEqual( + SimplePage::normalise('

    some text

    bar'), + 'some text bar'); + } + + function testSpaceNormalisation() { + $this->assertEqual( + SimplePage::normalise("\nOne\tTwo \nThree\t"), + 'One Two Three'); + } + + function testMultilinesCommentSuppression() { + $this->assertEqual( + SimplePage::normalise(''), + ''); + } + + function testCommentSuppression() { + $this->assertEqual( + SimplePage::normalise(''), + ''); + } + + function testJavascriptSuppression() { + $this->assertEqual( + SimplePage::normalise(''), + ''); + $this->assertEqual( + SimplePage::normalise(''), + ''); + $this->assertEqual( + SimplePage::normalise(''), + ''); + } + + function testTagSuppression() { + $this->assertEqual( + SimplePage::normalise('Hello'), + 'Hello'); + } + + function testAdjoiningTagSuppression() { + $this->assertEqual( + SimplePage::normalise('HelloGoodbye'), + 'HelloGoodbye'); + } + + function testExtractImageAltTextWithDifferentQuotes() { + $this->assertEqual( + SimplePage::normalise('One\'Two\'Three'), + 'One Two Three'); + } + + function testExtractImageAltTextMultipleTimes() { + $this->assertEqual( + SimplePage::normalise('OneTwoThree'), + 'One Two Three'); + } + + function testHtmlEntityTranslation() { + $this->assertEqual( + SimplePage::normalise('<>"&''), + '<>"&\''); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/parse_error_test.php b/application/libraries/simpletest/test/parse_error_test.php new file mode 100644 index 00000000000..c3ffb3d4205 --- /dev/null +++ b/application/libraries/simpletest/test/parse_error_test.php @@ -0,0 +1,9 @@ +addFile('test_with_parse_error.php'); +$test->run(new HtmlReporter()); +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/parsing_test.php b/application/libraries/simpletest/test/parsing_test.php new file mode 100644 index 00000000000..2c5e6cafe1d --- /dev/null +++ b/application/libraries/simpletest/test/parsing_test.php @@ -0,0 +1,642 @@ +whenVisiting('http://host/', 'Raw HTML'); + $this->assertEqual($page->getRaw(), 'Raw HTML'); + } + + function testTextAccessor() { + $page = $this->whenVisiting('http://host/', 'Some "messy" HTML'); + $this->assertEqual($page->getText(), 'Some "messy" HTML'); + } + + function testFramesetAbsence() { + $page = $this->whenVisiting('http://here/', ''); + $this->assertFalse($page->hasFrames()); + $this->assertIdentical($page->getFrameset(), false); + } + + function testPageWithNoUrlsGivesEmptyArrayOfLinks() { + $page = $this->whenVisiting('http://here/', '

    Stuff

    '); + $this->assertIdentical($page->getUrls(), array()); + } + + function testAddAbsoluteLink() { + $page = $this->whenVisiting('http://host', + 'Label'); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://somewhere.com'))); + } + + function testUrlLabelsHaveHtmlTagsStripped() { + $page = $this->whenVisiting('http://host', + 'Label'); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://somewhere.com'))); + } + + function testAddStrictRelativeLink() { + $page = $this->whenVisiting('http://host', + 'Label'); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://host/somewhere.php'))); + } + + function testAddBareRelativeLink() { + $page = $this->whenVisiting('http://host', + 'Label'); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://host/somewhere.php'))); + } + + function testAddRelativeLinkWithBaseTag() { + $raw = '' . + 'Label' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://www.lastcraft.com/stuff/somewhere.php'))); + } + + function testAddAbsoluteLinkWithBaseTag() { + $raw = '' . + 'Label' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://here.com/somewhere.php'))); + } + + function testCanFindLinkInsideForm() { + $raw = 'Label
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://host/somewhere.php'))); + } + + function testCanGetLinksByIdOrLabel() { + $raw = 'Label'; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + $page->getUrlsByLabel('Label'), + array(new SimpleUrl('http://host/somewhere.php'))); + $this->assertFalse($page->getUrlById(0)); + $this->assertEqual( + $page->getUrlById(33), + new SimpleUrl('http://host/somewhere.php')); + } + + function testCanFindLinkByNormalisedLabel() { + $raw = 'Long & thin'; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + $page->getUrlsByLabel('Long & thin'), + array(new SimpleUrl('http://host/somewhere.php'))); + } + + function testCanFindLinkByImageAltText() { + $raw = '<A picture>'; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual( + array_map(array($this, 'urlToString'), $page->getUrlsByLabel('')), + array('http://host/somewhere.php')); + } + + function testTitle() { + $page = $this->whenVisiting('http://host', + 'Me'); + $this->assertEqual($page->getTitle(), 'Me'); + } + + function testTitleWithEntityReference() { + $page = $this->whenVisiting('http://host', + 'Me&Me'); + $this->assertEqual($page->getTitle(), "Me&Me"); + } + + function testOnlyFramesInFramesetAreRecognised() { + $raw = + '' . + ' ' . + ' ' . + '' . + ''; + $page = $this->whenVisiting('http://here', $raw); + $this->assertTrue($page->hasFrames()); + $this->assertSameFrameset($page->getFrameset(), array( + 1 => new SimpleUrl('http://here/2.html'), + 2 => new SimpleUrl('http://here/3.html'))); + } + + function testReadsNamesInFrames() { + $raw = + '' . + ' ' . + ' ' . + ' ' . + ' ' . + ''; + $page = $this->whenVisiting('http://here', $raw); + $this->assertTrue($page->hasFrames()); + $this->assertSameFrameset($page->getFrameset(), array( + 1 => new SimpleUrl('http://here/1.html'), + 'A' => new SimpleUrl('http://here/2.html'), + 'B' => new SimpleUrl('http://here/3.html'), + 4 => new SimpleUrl('http://here/4.html'))); + } + + function testRelativeFramesRespectBaseTag() { + $raw = ''; + $page = $this->whenVisiting('http://here', $raw); + $this->assertSameFrameset( + $page->getFrameset(), + array(1 => new SimpleUrl('https://there.com/stuff/1.html'))); + } + + function testSingleFrameInNestedFrameset() { + $raw = '' . + '' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->hasFrames()); + $this->assertIdentical( + $page->getFrameset(), + array(1 => new SimpleUrl('http://host/a.html'))); + } + + function testFramesCollectedWithNestedFramesetTags() { + $raw = '' . + '' . + '' . + '' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->hasFrames()); + $this->assertIdentical($page->getFrameset(), array( + 1 => new SimpleUrl('http://host/a.html'), + 2 => new SimpleUrl('http://host/b.html'), + 3 => new SimpleUrl('http://host/c.html'))); + } + + function testNamedFrames() { + $raw = '' . + '' . + '' . + '' . + '' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->hasFrames()); + $this->assertIdentical($page->getFrameset(), array( + 1 => new SimpleUrl('http://host/a.html'), + '_one' => new SimpleUrl('http://host/b.html'), + 3 => new SimpleUrl('http://host/c.html'), + '_two' => new SimpleUrl('http://host/d.html'))); + } + + function testCanReadElementOfCompleteForm() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('here')), "Hello"); + } + + function testCanReadElementOfUnclosedForm() { + $raw = '
    ' . + '' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('here')), "Hello"); + } + + function testCanReadElementByLabel() { + $raw = '' . + '' . + ''; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('Where')), "Hello"); + } + + function testCanFindFormByLabel() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertNull($page->getFormBySubmit(new SimpleByLabel('submit'))); + $this->assertNull($page->getFormBySubmit(new SimpleByName('submit'))); + $this->assertIsA( + $page->getFormBySubmit(new SimpleByLabel('Submit')), + 'SimpleForm'); + } + + function testConfirmSubmitAttributesAreCaseSensitive() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertIsA( + $page->getFormBySubmit(new SimpleByName('S')), + 'SimpleForm'); + $this->assertIsA( + $page->getFormBySubmit(new SimpleByLabel('S')), + 'SimpleForm'); + } + + function testCanFindFormByImage() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertIsA( + $page->getFormByImage(new SimpleByLabel('Label')), + 'SimpleForm'); + $this->assertIsA( + $page->getFormByImage(new SimpleByName('me')), + 'SimpleForm'); + $this->assertIsA( + $page->getFormByImage(new SimpleById(100)), + 'SimpleForm'); + } + + function testCanFindFormByButtonTag() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertNull($page->getFormBySubmit(new SimpleByLabel('b'))); + $this->assertNull($page->getFormBySubmit(new SimpleByLabel('B'))); + $this->assertIsA( + $page->getFormBySubmit(new SimpleByName('b')), + 'SimpleForm'); + $this->assertIsA( + $page->getFormBySubmit(new SimpleByLabel('BBB')), + 'SimpleForm'); + } + + function testCanFindFormById() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertNull($page->getFormById(54)); + $this->assertIsA($page->getFormById(55), 'SimpleForm'); + } + + function testFormCanBeSubmitted() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $form = $page->getFormBySubmit(new SimpleByLabel('Submit')); + $this->assertEqual( + $form->submitButton(new SimpleByLabel('Submit')), + new SimpleGetEncoding(array('s' => 'Submit'))); + } + + function testUnparsedTagDoesNotCrash() { + $raw = '
    '; + $this->whenVisiting('http://host', $raw); + } + + function testReadingTextField() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertNull($page->getField(new SimpleByName('missing'))); + $this->assertIdentical($page->getField(new SimpleByName('a')), ''); + $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb'); + } + + function testEntitiesAreDecodedInDefaultTextFieldValue() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), '&\'"<>'); + } + + function testReadingTextFieldIsCaseInsensitive() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertNull($page->getField(new SimpleByName('missing'))); + $this->assertIdentical($page->getField(new SimpleByName('a')), ''); + $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb'); + } + + function testSettingTextField() { + $raw = '
    ' . + '' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa')); + $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); + $this->assertTrue($page->setField(new SimpleById(3), 'bbb')); + $this->assertEqual($page->getField(new SimpleBYId(3)), 'bbb'); + $this->assertFalse($page->setField(new SimpleByName('z'), 'zzz')); + $this->assertNull($page->getField(new SimpleByName('z'))); + } + + function testSettingTextFieldByEnclosingLabel() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), 'A'); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); + $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa')); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa'); + } + + function testLabelsWithoutForDoNotAttachToInputsWithNoId() { + $raw = '
    + + +
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabelOrName('Text A')), 'one'); + $this->assertEqual($page->getField(new SimpleByLabelOrName('Text B')), 'two'); + $this->assertTrue($page->setField(new SimpleByLabelOrName('Text A'), '1')); + $this->assertTrue($page->setField(new SimpleByLabelOrName('Text B'), '2')); + $this->assertEqual($page->getField(new SimpleByLabelOrName('Text A')), '1'); + $this->assertEqual($page->getField(new SimpleByLabelOrName('Text B')), '2'); + } + + function testGettingTextFieldByEnclosingLabelWithConflictingOtherFields() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), 'A'); + $this->assertEqual($page->getField(new SimpleByName('b')), 'B'); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); + } + + function testSettingTextFieldByExternalLabel() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); + $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa')); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa'); + } + + function testReadingTextArea() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); + } + + function testEntitiesAreDecodedInTextareaValue() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), '&\'"<>'); + } + + function testNewlinesPreservedInTextArea() { + $raw = "
    "; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), "hello\r\nworld"); + } + + function testWhitespacePreservedInTextArea() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), ' '); + } + + function testComplexWhitespaceInTextArea() { + $raw = "\n" . + " \n" . + " \n" . + "
    \n". + " \n" . + "
    \n" . + " \n" . + ""; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('c')), " "); + } + + function testSettingTextArea() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByName('a'), 'AAA')); + $this->assertEqual($page->getField(new SimpleByName('a')), 'AAA'); + } + + function testDontIncludeTextAreaContentInLabel() { + $raw = '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('Text area C')), 'mouse'); + } + + function testSettingSelectionField() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), 'bbb'); + $this->assertFalse($page->setField(new SimpleByName('a'), 'ccc')); + $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa')); + $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa'); + } + + function testSelectionOptionsAreNormalised() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('a')), 'Big bold'); + $this->assertTrue($page->setField(new SimpleByName('a'), 'small italic')); + $this->assertEqual($page->getField(new SimpleByName('a')), 'small italic'); + } + + function testCanParseBlankOptions() { + $raw = '
    + +
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByName('d'), '')); + } + + function testTwoSelectionFieldsAreIndependent() { + $raw = '
    + + +
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByName('d'), 'd2')); + $this->assertTrue($page->setField(new SimpleByName('h'), 'h1')); + $this->assertEqual($page->getField(new SimpleByName('d')), 'd2'); + } + + function testEmptyOptionDoesNotScrewUpTwoSelectionFields() { + $raw = '
    + + +
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByName('d'), 'd2')); + $this->assertTrue($page->setField(new SimpleByName('h'), 'h1')); + $this->assertEqual($page->getField(new SimpleByName('d')), 'd2'); + } + + function testSettingSelectionFieldByEnclosingLabel() { + $raw = '
    ' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A'); + $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'B')); + $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'B'); + } + + function testTwoSelectionFieldsWithLabelsAreIndependent() { + $raw = '
    + + +
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertTrue($page->setField(new SimpleByLabel('Labelled D'), 'd2')); + $this->assertTrue($page->setField(new SimpleByLabel('Labelled H'), 'h1')); + $this->assertEqual($page->getField(new SimpleByLabel('Labelled D')), 'd2'); + } + + function testSettingRadioButtonByEnclosingLabel() { + $raw = '
    ' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('A')), 'a'); + $this->assertTrue($page->setField(new SimpleBylabel('B'), 'b')); + $this->assertEqual($page->getField(new SimpleByLabel('B')), 'b'); + } + + function testCanParseInputsWithAllKindsOfAttributeQuoting() { + $raw = '
    ' . + '' . + '' . + '' . + '
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByName('first')), 'one'); + $this->assertEqual($page->getField(new SimpleByName('second')), false); + $this->assertEqual($page->getField(new SimpleByName('third')), 'three'); + } + + function urlToString($url) { + return $url->asString(); + } + + function assertSameFrameset($actual, $expected) { + $this->assertIdentical(array_map(array($this, 'urlToString'), $actual), + array_map(array($this, 'urlToString'), $expected)); + } +} + +class TestOfParsingUsingPhpParser extends TestOfParsing { + + function whenVisiting($url, $content) { + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getContent', $content); + $response->setReturnValue('getUrl', new SimpleUrl($url)); + $builder = new SimplePhpPageBuilder(); + return $builder->parse($response); + } + + function testNastyTitle() { + $page = $this->whenVisiting('http://host', + ' <b>Me&Me '); + $this->assertEqual($page->getTitle(), "Me&Me"); + } + + function testLabelShouldStopAtClosingLabelTag() { + $raw = '
    stuff
    '; + $page = $this->whenVisiting('http://host', $raw); + $this->assertEqual($page->getField(new SimpleByLabel('startend')), 'stuff'); + } +} + +class TestOfParsingUsingTidyParser extends TestOfParsing { + + function skip() { + $this->skipUnless(extension_loaded('tidy'), 'Install \'tidy\' php extension to enable html tidy based parser'); + } + + function whenVisiting($url, $content) { + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getContent', $content); + $response->setReturnValue('getUrl', new SimpleUrl($url)); + $builder = new SimpleTidyPageBuilder(); + return $builder->parse($response); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/php_parser_test.php b/application/libraries/simpletest/test/php_parser_test.php new file mode 100644 index 00000000000..d95c7d06a60 --- /dev/null +++ b/application/libraries/simpletest/test/php_parser_test.php @@ -0,0 +1,489 @@ +assertFalse($regex->match("Hello", $match)); + $this->assertEqual($match, ""); + } + + function testNoSubject() { + $regex = new ParallelRegex(false); + $regex->addPattern(".*"); + $this->assertTrue($regex->match("", $match)); + $this->assertEqual($match, ""); + } + + function testMatchAll() { + $regex = new ParallelRegex(false); + $regex->addPattern(".*"); + $this->assertTrue($regex->match("Hello", $match)); + $this->assertEqual($match, "Hello"); + } + + function testCaseSensitive() { + $regex = new ParallelRegex(true); + $regex->addPattern("abc"); + $this->assertTrue($regex->match("abcdef", $match)); + $this->assertEqual($match, "abc"); + $this->assertTrue($regex->match("AAABCabcdef", $match)); + $this->assertEqual($match, "abc"); + } + + function testCaseInsensitive() { + $regex = new ParallelRegex(false); + $regex->addPattern("abc"); + $this->assertTrue($regex->match("abcdef", $match)); + $this->assertEqual($match, "abc"); + $this->assertTrue($regex->match("AAABCabcdef", $match)); + $this->assertEqual($match, "ABC"); + } + + function testMatchMultiple() { + $regex = new ParallelRegex(true); + $regex->addPattern("abc"); + $regex->addPattern("ABC"); + $this->assertTrue($regex->match("abcdef", $match)); + $this->assertEqual($match, "abc"); + $this->assertTrue($regex->match("AAABCabcdef", $match)); + $this->assertEqual($match, "ABC"); + $this->assertFalse($regex->match("Hello", $match)); + } + + function testPatternLabels() { + $regex = new ParallelRegex(false); + $regex->addPattern("abc", "letter"); + $regex->addPattern("123", "number"); + $this->assertIdentical($regex->match("abcdef", $match), "letter"); + $this->assertEqual($match, "abc"); + $this->assertIdentical($regex->match("0123456789", $match), "number"); + $this->assertEqual($match, "123"); + } +} + +class TestOfStateStack extends UnitTestCase { + + function testStartState() { + $stack = new SimpleStateStack("one"); + $this->assertEqual($stack->getCurrent(), "one"); + } + + function testExhaustion() { + $stack = new SimpleStateStack("one"); + $this->assertFalse($stack->leave()); + } + + function testStateMoves() { + $stack = new SimpleStateStack("one"); + $stack->enter("two"); + $this->assertEqual($stack->getCurrent(), "two"); + $stack->enter("three"); + $this->assertEqual($stack->getCurrent(), "three"); + $this->assertTrue($stack->leave()); + $this->assertEqual($stack->getCurrent(), "two"); + $stack->enter("third"); + $this->assertEqual($stack->getCurrent(), "third"); + $this->assertTrue($stack->leave()); + $this->assertTrue($stack->leave()); + $this->assertEqual($stack->getCurrent(), "one"); + } +} + +class TestParser { + + function accept() { + } + + function a() { + } + + function b() { + } +} +Mock::generate('TestParser'); + +class TestOfLexer extends UnitTestCase { + + function testEmptyPage() { + $handler = new MockTestParser(); + $handler->expectNever("accept"); + $handler->setReturnValue("accept", true); + $handler->expectNever("accept"); + $handler->setReturnValue("accept", true); + $lexer = new SimpleLexer($handler); + $lexer->addPattern("a+"); + $this->assertTrue($lexer->parse("")); + } + + function testSinglePattern() { + $handler = new MockTestParser(); + $handler->expectAt(0, "accept", array("aaa", LEXER_MATCHED)); + $handler->expectAt(1, "accept", array("x", LEXER_UNMATCHED)); + $handler->expectAt(2, "accept", array("a", LEXER_MATCHED)); + $handler->expectAt(3, "accept", array("yyy", LEXER_UNMATCHED)); + $handler->expectAt(4, "accept", array("a", LEXER_MATCHED)); + $handler->expectAt(5, "accept", array("x", LEXER_UNMATCHED)); + $handler->expectAt(6, "accept", array("aaa", LEXER_MATCHED)); + $handler->expectAt(7, "accept", array("z", LEXER_UNMATCHED)); + $handler->expectCallCount("accept", 8); + $handler->setReturnValue("accept", true); + $lexer = new SimpleLexer($handler); + $lexer->addPattern("a+"); + $this->assertTrue($lexer->parse("aaaxayyyaxaaaz")); + } + + function testMultiplePattern() { + $handler = new MockTestParser(); + $target = array("a", "b", "a", "bb", "x", "b", "a", "xxxxxx", "a", "x"); + for ($i = 0; $i < count($target); $i++) { + $handler->expectAt($i, "accept", array($target[$i], '*')); + } + $handler->expectCallCount("accept", count($target)); + $handler->setReturnValue("accept", true); + $lexer = new SimpleLexer($handler); + $lexer->addPattern("a+"); + $lexer->addPattern("b+"); + $this->assertTrue($lexer->parse("ababbxbaxxxxxxax")); + } +} + +class TestOfLexerModes extends UnitTestCase { + + function testIsolatedPattern() { + $handler = new MockTestParser(); + $handler->expectAt(0, "a", array("a", LEXER_MATCHED)); + $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED)); + $handler->expectAt(2, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(3, "a", array("bxb", LEXER_UNMATCHED)); + $handler->expectAt(4, "a", array("aaa", LEXER_MATCHED)); + $handler->expectAt(5, "a", array("x", LEXER_UNMATCHED)); + $handler->expectAt(6, "a", array("aaaa", LEXER_MATCHED)); + $handler->expectAt(7, "a", array("x", LEXER_UNMATCHED)); + $handler->expectCallCount("a", 8); + $handler->setReturnValue("a", true); + $lexer = new SimpleLexer($handler, "a"); + $lexer->addPattern("a+", "a"); + $lexer->addPattern("b+", "b"); + $this->assertTrue($lexer->parse("abaabxbaaaxaaaax")); + } + + function testModeChange() { + $handler = new MockTestParser(); + $handler->expectAt(0, "a", array("a", LEXER_MATCHED)); + $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED)); + $handler->expectAt(2, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(3, "a", array("b", LEXER_UNMATCHED)); + $handler->expectAt(4, "a", array("aaa", LEXER_MATCHED)); + $handler->expectAt(0, "b", array(":", LEXER_ENTER)); + $handler->expectAt(1, "b", array("a", LEXER_UNMATCHED)); + $handler->expectAt(2, "b", array("b", LEXER_MATCHED)); + $handler->expectAt(3, "b", array("a", LEXER_UNMATCHED)); + $handler->expectAt(4, "b", array("bb", LEXER_MATCHED)); + $handler->expectAt(5, "b", array("a", LEXER_UNMATCHED)); + $handler->expectAt(6, "b", array("bbb", LEXER_MATCHED)); + $handler->expectAt(7, "b", array("a", LEXER_UNMATCHED)); + $handler->expectCallCount("a", 5); + $handler->expectCallCount("b", 8); + $handler->setReturnValue("a", true); + $handler->setReturnValue("b", true); + $lexer = new SimpleLexer($handler, "a"); + $lexer->addPattern("a+", "a"); + $lexer->addEntryPattern(":", "a", "b"); + $lexer->addPattern("b+", "b"); + $this->assertTrue($lexer->parse("abaabaaa:ababbabbba")); + } + + function testNesting() { + $handler = new MockTestParser(); + $handler->setReturnValue("a", true); + $handler->setReturnValue("b", true); + $handler->expectAt(0, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED)); + $handler->expectAt(2, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(3, "a", array("b", LEXER_UNMATCHED)); + $handler->expectAt(0, "b", array("(", LEXER_ENTER)); + $handler->expectAt(1, "b", array("bb", LEXER_MATCHED)); + $handler->expectAt(2, "b", array("a", LEXER_UNMATCHED)); + $handler->expectAt(3, "b", array("bb", LEXER_MATCHED)); + $handler->expectAt(4, "b", array(")", LEXER_EXIT)); + $handler->expectAt(4, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(5, "a", array("b", LEXER_UNMATCHED)); + $handler->expectCallCount("a", 6); + $handler->expectCallCount("b", 5); + $lexer = new SimpleLexer($handler, "a"); + $lexer->addPattern("a+", "a"); + $lexer->addEntryPattern("(", "a", "b"); + $lexer->addPattern("b+", "b"); + $lexer->addExitPattern(")", "b"); + $this->assertTrue($lexer->parse("aabaab(bbabb)aab")); + } + + function testSingular() { + $handler = new MockTestParser(); + $handler->setReturnValue("a", true); + $handler->setReturnValue("b", true); + $handler->expectAt(0, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(1, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(2, "a", array("xx", LEXER_UNMATCHED)); + $handler->expectAt(3, "a", array("xx", LEXER_UNMATCHED)); + $handler->expectAt(0, "b", array("b", LEXER_SPECIAL)); + $handler->expectAt(1, "b", array("bbb", LEXER_SPECIAL)); + $handler->expectCallCount("a", 4); + $handler->expectCallCount("b", 2); + $lexer = new SimpleLexer($handler, "a"); + $lexer->addPattern("a+", "a"); + $lexer->addSpecialPattern("b+", "a", "b"); + $this->assertTrue($lexer->parse("aabaaxxbbbxx")); + } + + function testUnwindTooFar() { + $handler = new MockTestParser(); + $handler->setReturnValue("a", true); + $handler->expectAt(0, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(1, "a", array(")", LEXER_EXIT)); + $handler->expectCallCount("a", 2); + $lexer = new SimpleLexer($handler, "a"); + $lexer->addPattern("a+", "a"); + $lexer->addExitPattern(")", "a"); + $this->assertFalse($lexer->parse("aa)aa")); + } +} + +class TestOfLexerHandlers extends UnitTestCase { + + function testModeMapping() { + $handler = new MockTestParser(); + $handler->setReturnValue("a", true); + $handler->expectAt(0, "a", array("aa", LEXER_MATCHED)); + $handler->expectAt(1, "a", array("(", LEXER_ENTER)); + $handler->expectAt(2, "a", array("bb", LEXER_MATCHED)); + $handler->expectAt(3, "a", array("a", LEXER_UNMATCHED)); + $handler->expectAt(4, "a", array("bb", LEXER_MATCHED)); + $handler->expectAt(5, "a", array(")", LEXER_EXIT)); + $handler->expectAt(6, "a", array("b", LEXER_UNMATCHED)); + $handler->expectCallCount("a", 7); + $lexer = new SimpleLexer($handler, "mode_a"); + $lexer->addPattern("a+", "mode_a"); + $lexer->addEntryPattern("(", "mode_a", "mode_b"); + $lexer->addPattern("b+", "mode_b"); + $lexer->addExitPattern(")", "mode_b"); + $lexer->mapHandler("mode_a", "a"); + $lexer->mapHandler("mode_b", "a"); + $this->assertTrue($lexer->parse("aa(bbabb)b")); + } +} + +class TestOfSimpleHtmlLexer extends UnitTestCase { + + function &createParser() { + $parser = new MockSimpleHtmlSaxParser(); + $parser->setReturnValue('acceptStartToken', true); + $parser->setReturnValue('acceptEndToken', true); + $parser->setReturnValue('acceptAttributeToken', true); + $parser->setReturnValue('acceptEntityToken', true); + $parser->setReturnValue('acceptTextToken', true); + $parser->setReturnValue('ignore', true); + return $parser; + } + + function testNoContent() { + $parser = $this->createParser(); + $parser->expectNever('acceptStartToken'); + $parser->expectNever('acceptEndToken'); + $parser->expectNever('acceptAttributeToken'); + $parser->expectNever('acceptEntityToken'); + $parser->expectNever('acceptTextToken'); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse('')); + } + + function testUninteresting() { + $parser = $this->createParser(); + $parser->expectOnce('acceptTextToken', array('', '*')); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse('')); + } + + function testSkipCss() { + $parser = $this->createParser(); + $parser->expectNever('acceptTextToken'); + $parser->expectAtLeastOnce('ignore'); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse("")); + } + + function testSkipJavaScript() { + $parser = $this->createParser(); + $parser->expectNever('acceptTextToken'); + $parser->expectAtLeastOnce('ignore'); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse("")); + } + + function testSkipHtmlComments() { + $parser = $this->createParser(); + $parser->expectNever('acceptTextToken'); + $parser->expectAtLeastOnce('ignore'); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse("")); + } + + function testTagWithNoAttributes() { + $parser = $this->createParser(); + $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('>', '*')); + $parser->expectCallCount('acceptStartToken', 2); + $parser->expectOnce('acceptTextToken', array('Hello', '*')); + $parser->expectOnce('acceptEndToken', array('', '*')); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse('Hello')); + } + + function testTagWithAttributes() { + $parser = $this->createParser(); + $parser->expectOnce('acceptTextToken', array('label', '*')); + $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('href', '*')); + $parser->expectAt(2, 'acceptStartToken', array('>', '*')); + $parser->expectCallCount('acceptStartToken', 3); + $parser->expectAt(0, 'acceptAttributeToken', array('= "', '*')); + $parser->expectAt(1, 'acceptAttributeToken', array('here.html', '*')); + $parser->expectAt(2, 'acceptAttributeToken', array('"', '*')); + $parser->expectCallCount('acceptAttributeToken', 3); + $parser->expectOnce('acceptEndToken', array('
    ', '*')); + $lexer = new SimpleHtmlLexer($parser); + $this->assertTrue($lexer->parse('label')); + } +} + +class TestOfHtmlSaxParser extends UnitTestCase { + + function createListener() { + $listener = new MockSimplePhpPageBuilder(); + $listener->setReturnValue('startElement', true); + $listener->setReturnValue('addContent', true); + $listener->setReturnValue('endElement', true); + return $listener; + } + + function testFramesetTag() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('frameset', array())); + $listener->expectOnce('addContent', array('Frames')); + $listener->expectOnce('endElement', array('frameset')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('Frames')); + } + + function testTagWithUnquotedAttributes() { + $listener = $this->createListener(); + $listener->expectOnce( + 'startElement', + array('input', array('name' => 'a.b.c', 'value' => 'd'))); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('')); + } + + function testTagInsideContent() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('a', array())); + $listener->expectAt(0, 'addContent', array('')); + $listener->expectAt(1, 'addContent', array('')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('')); + } + + function testTagWithInternalContent() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('a', array())); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('a')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('label')); + } + + function testLinkAddress() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('a', array('href' => 'here.html'))); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('a')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse("label")); + } + + function testEncodedAttribute() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('a', array('href' => 'here&there.html'))); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('a')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse("label")); + } + + function testTagWithId() { + $listener = $this->createListener(); + $listener->expectOnce('startElement', array('a', array('id' => '0'))); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('a')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('label')); + } + + function testTagWithEmptyAttributes() { + $listener = $this->createListener(); + $listener->expectOnce( + 'startElement', + array('option', array('value' => '', 'selected' => ''))); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('option')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('')); + } + + function testComplexTagWithLotsOfCaseVariations() { + $listener = $this->createListener(); + $listener->expectOnce( + 'startElement', + array('a', array('href' => 'here.html', 'style' => "'cool'"))); + $listener->expectOnce('addContent', array('label')); + $listener->expectOnce('endElement', array('a')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('label')); + } + + function testXhtmlSelfClosingTag() { + $listener = $this->createListener(); + $listener->expectOnce( + 'startElement', + array('input', array('type' => 'submit', 'name' => 'N', 'value' => 'V'))); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse('')); + } + + function testNestedFrameInFrameset() { + $listener = $this->createListener(); + $listener->expectAt(0, 'startElement', array('frameset', array())); + $listener->expectAt(1, 'startElement', array('frame', array('src' => 'frame.html'))); + $listener->expectCallCount('startElement', 2); + $listener->expectOnce('addContent', array('Hello')); + $listener->expectOnce('endElement', array('frameset')); + $parser = new SimpleHtmlSaxParser($listener); + $this->assertTrue($parser->parse( + 'Hello')); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/reflection_php4_test.php b/application/libraries/simpletest/test/reflection_php4_test.php new file mode 100644 index 00000000000..8ee211b961b --- /dev/null +++ b/application/libraries/simpletest/test/reflection_php4_test.php @@ -0,0 +1,61 @@ +assertTrue($reflection->classOrInterfaceExists()); + $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload()); + } + + function testClassNonExistence() { + $reflection = new SimpleReflection('UnknownThing'); + $this->assertFalse($reflection->classOrInterfaceExists()); + $this->assertFalse($reflection->classOrInterfaceExistsSansAutoload()); + } + + function testDetectionOfInterfacesAlwaysFalse() { + $reflection = new SimpleReflection('AnyOldThing'); + $this->assertFalse($reflection->isAbstract()); + $this->assertFalse($reflection->isInterface()); + } + + function testFindingParentClass() { + $reflection = new SimpleReflection('AnyOldChildThing'); + $this->assertEqual(strtolower($reflection->getParent()), 'anyoldthing'); + } + + function testMethodsListFromClass() { + $reflection = new SimpleReflection('AnyOldThing'); + $methods = $reflection->getMethods(); + $this->assertEqualIgnoringCase($methods[0], 'aMethod'); + } + + function testNoInterfacesForPHP4() { + $reflection = new SimpleReflection('AnyOldThing'); + $this->assertEqual( + $reflection->getInterfaces(), + array()); + } + + function testMostGeneralPossibleSignature() { + $reflection = new SimpleReflection('AnyOldThing'); + $this->assertEqualIgnoringCase( + $reflection->getSignature('aMethod'), + 'function &aMethod()'); + } + + function assertEqualIgnoringCase($a, $b) { + return $this->assertEqual(strtolower($a), strtolower($b)); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/reflection_php5_test.php b/application/libraries/simpletest/test/reflection_php5_test.php new file mode 100644 index 00000000000..d9f46e6db78 --- /dev/null +++ b/application/libraries/simpletest/test/reflection_php5_test.php @@ -0,0 +1,263 @@ +assertTrue($reflection->classOrInterfaceExists()); + $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload()); + $this->assertFalse($reflection->isAbstract()); + $this->assertFalse($reflection->isInterface()); + } + + function testClassNonExistence() { + $reflection = new SimpleReflection('UnknownThing'); + $this->assertFalse($reflection->classOrInterfaceExists()); + $this->assertFalse($reflection->classOrInterfaceExistsSansAutoload()); + } + + function testDetectionOfAbstractClass() { + $reflection = new SimpleReflection('AnyOldClass'); + $this->assertTrue($reflection->isAbstract()); + } + + function testDetectionOfFinalMethods() { + $reflection = new SimpleReflection('AnyOldClass'); + $this->assertFalse($reflection->hasFinal()); + $reflection = new SimpleReflection('AnyOldLeafClassWithAFinal'); + $this->assertTrue($reflection->hasFinal()); + } + + function testFindingParentClass() { + $reflection = new SimpleReflection('AnyOldSubclass'); + $this->assertEqual($reflection->getParent(), 'AnyOldImplementation'); + } + + function testInterfaceExistence() { + $reflection = new SimpleReflection('AnyOldInterface'); + $this->assertTrue($reflection->classOrInterfaceExists()); + $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload()); + $this->assertTrue($reflection->isInterface()); + } + + function testMethodsListFromClass() { + $reflection = new SimpleReflection('AnyOldClass'); + $this->assertIdentical($reflection->getMethods(), array('aMethod')); + } + + function testMethodsListFromInterface() { + $reflection = new SimpleReflection('AnyOldInterface'); + $this->assertIdentical($reflection->getMethods(), array('aMethod')); + $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod')); + } + + function testMethodsComeFromDescendentInterfacesASWell() { + $reflection = new SimpleReflection('AnyDescendentInterface'); + $this->assertIdentical($reflection->getMethods(), array('aMethod')); + } + + function testCanSeparateInterfaceMethodsFromOthers() { + $reflection = new SimpleReflection('AnyOldImplementation'); + $this->assertIdentical($reflection->getMethods(), array('aMethod', 'extraMethod')); + $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod')); + } + + function testMethodsComeFromDescendentInterfacesInAbstractClass() { + $reflection = new SimpleReflection('AnyAbstractImplementation'); + $this->assertIdentical($reflection->getMethods(), array('aMethod')); + } + + function testInterfaceHasOnlyItselfToImplement() { + $reflection = new SimpleReflection('AnyOldInterface'); + $this->assertEqual( + $reflection->getInterfaces(), + array('AnyOldInterface')); + } + + function testInterfacesListedForClass() { + $reflection = new SimpleReflection('AnyOldImplementation'); + $this->assertEqual( + $reflection->getInterfaces(), + array('AnyOldInterface')); + } + + function testInterfacesListedForSubclass() { + $reflection = new SimpleReflection('AnyOldSubclass'); + $this->assertEqual( + $reflection->getInterfaces(), + array('AnyOldInterface')); + } + + function testNoParameterCreationWhenNoInterface() { + $reflection = new SimpleReflection('AnyOldArgumentClass'); + $function = $reflection->getSignature('aMethod'); + if (version_compare(phpversion(), '5.0.2', '<=')) { + $this->assertEqual('function amethod($argument)', strtolower($function)); + } else { + $this->assertEqual('function aMethod($argument)', $function); + } + } + + function testParameterCreationWithoutTypeHinting() { + $reflection = new SimpleReflection('AnyOldArgumentImplementation'); + $function = $reflection->getSignature('aMethod'); + if (version_compare(phpversion(), '5.0.2', '<=')) { + $this->assertEqual('function amethod(AnyOldInterface $argument)', $function); + } else { + $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function); + } + } + + function testParameterCreationForTypeHinting() { + $reflection = new SimpleReflection('AnyOldTypeHintedClass'); + $function = $reflection->getSignature('aMethod'); + if (version_compare(phpversion(), '5.0.2', '<=')) { + $this->assertEqual('function amethod(AnyOldInterface $argument)', $function); + } else { + $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function); + } + } + + function testIssetFunctionSignature() { + $reflection = new SimpleReflection('AnyOldOverloadedClass'); + $function = $reflection->getSignature('__isset'); + $this->assertEqual('function __isset($key)', $function); + } + + function testUnsetFunctionSignature() { + $reflection = new SimpleReflection('AnyOldOverloadedClass'); + $function = $reflection->getSignature('__unset'); + $this->assertEqual('function __unset($key)', $function); + } + + function testProperlyReflectsTheFinalInterfaceWhenObjectImplementsAnExtendedInterface() { + $reflection = new SimpleReflection('AnyDescendentImplementation'); + $interfaces = $reflection->getInterfaces(); + $this->assertEqual(1, count($interfaces)); + $this->assertEqual('AnyDescendentInterface', array_shift($interfaces)); + } + + function testCreatingSignatureForAbstractMethod() { + $reflection = new SimpleReflection('AnotherOldAbstractClass'); + $this->assertEqual($reflection->getSignature('aMethod'), 'function aMethod(AnyOldInterface $argument)'); + } + + function testCanProperlyGenerateStaticMethodSignatures() { + $reflection = new SimpleReflection('AnyOldClassWithStaticMethods'); + $this->assertEqual('static function aStatic()', $reflection->getSignature('aStatic')); + $this->assertEqual( + 'static function aStaticWithParameters($arg1, $arg2)', + $reflection->getSignature('aStaticWithParameters') + ); + } +} + +class TestOfReflectionWithTypeHints extends UnitTestCase { + function skip() { + $this->skipIf(version_compare(phpversion(), '5.1.0', '<'), 'Reflection with type hints only tested for PHP 5.1.0 and above'); + } + + function testParameterCreationForTypeHintingWithArray() { + eval('interface AnyOldArrayTypeHintedInterface { + function amethod(array $argument); + } + class AnyOldArrayTypeHintedClass implements AnyOldArrayTypeHintedInterface { + function amethod(array $argument) {} + }'); + $reflection = new SimpleReflection('AnyOldArrayTypeHintedClass'); + $function = $reflection->getSignature('amethod'); + $this->assertEqual('function amethod(array $argument)', $function); + } +} + +class TestOfAbstractsWithAbstractMethods extends UnitTestCase { + function testCanProperlyGenerateAbstractMethods() { + $reflection = new SimpleReflection('AnyOldAbstractClassWithAbstractMethods'); + $this->assertEqual( + 'function anAbstract()', + $reflection->getSignature('anAbstract') + ); + $this->assertEqual( + 'function anAbstractWithParameter($foo)', + $reflection->getSignature('anAbstractWithParameter') + ); + $this->assertEqual( + 'function anAbstractWithMultipleParameters($foo, $bar)', + $reflection->getSignature('anAbstractWithMultipleParameters') + ); + } +} + +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/remote_test.php b/application/libraries/simpletest/test/remote_test.php new file mode 100644 index 00000000000..5f3f96a4de9 --- /dev/null +++ b/application/libraries/simpletest/test/remote_test.php @@ -0,0 +1,19 @@ +add(new RemoteTestCase($test_url . '?xml=yes', $test_url . '?xml=yes&dry=yes')); +if (SimpleReporter::inCli()) { + exit ($test->run(new TextReporter()) ? 0 : 1); +} +$test->run(new HtmlReporter()); diff --git a/application/libraries/simpletest/test/shell_test.php b/application/libraries/simpletest/test/shell_test.php new file mode 100644 index 00000000000..d1d769a6795 --- /dev/null +++ b/application/libraries/simpletest/test/shell_test.php @@ -0,0 +1,38 @@ +assertIdentical($shell->execute('echo Hello'), 0); + $this->assertPattern('/Hello/', $shell->getOutput()); + } + + function testBadCommand() { + $shell = new SimpleShell(); + $this->assertNotEqual($ret = $shell->execute('blurgh! 2>&1'), 0); + } +} + +class TestOfShellTesterAndShell extends ShellTestCase { + + function testEcho() { + $this->assertTrue($this->execute('echo Hello')); + $this->assertExitCode(0); + $this->assertoutput('Hello'); + } + + function testFileExistence() { + $this->assertFileExists(dirname(__FILE__) . '/all_tests.php'); + $this->assertFileNotExists('wibble'); + } + + function testFilePatterns() { + $this->assertFilePattern('/all[_ ]tests/i', dirname(__FILE__) . '/all_tests.php'); + $this->assertNoFilePattern('/sputnik/i', dirname(__FILE__) . '/all_tests.php'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/shell_tester_test.php b/application/libraries/simpletest/test/shell_tester_test.php new file mode 100644 index 00000000000..b12c602a39f --- /dev/null +++ b/application/libraries/simpletest/test/shell_tester_test.php @@ -0,0 +1,42 @@ +mock_shell; + } + + function testGenericEquality() { + $this->assertEqual('a', 'a'); + $this->assertNotEqual('a', 'A'); + } + + function testExitCode() { + $this->mock_shell = new MockSimpleShell(); + $this->mock_shell->setReturnValue('execute', 0); + $this->mock_shell->expectOnce('execute', array('ls')); + $this->assertTrue($this->execute('ls')); + $this->assertExitCode(0); + } + + function testOutput() { + $this->mock_shell = new MockSimpleShell(); + $this->mock_shell->setReturnValue('execute', 0); + $this->mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n"); + $this->assertOutput("Line 1\nLine 2\n"); + } + + function testOutputPatterns() { + $this->mock_shell = new MockSimpleShell(); + $this->mock_shell->setReturnValue('execute', 0); + $this->mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n"); + $this->assertOutputPattern('/line/i'); + $this->assertNoOutputPattern('/line 2/'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/simpletest_test.php b/application/libraries/simpletest/test/simpletest_test.php new file mode 100644 index 00000000000..daa65c6f472 --- /dev/null +++ b/application/libraries/simpletest/test/simpletest_test.php @@ -0,0 +1,58 @@ +fail('Should be ignored'); + } +} + +class ShouldNeverBeRunEither extends ShouldNeverBeRun { } + +class TestOfStackTrace extends UnitTestCase { + + function testCanFindAssertInTrace() { + $trace = new SimpleStackTrace(array('assert')); + $this->assertEqual( + $trace->traceMethod(array(array( + 'file' => '/my_test.php', + 'line' => 24, + 'function' => 'assertSomething'))), + ' at [/my_test.php line 24]'); + } +} + +class DummyResource { } + +class TestOfContext extends UnitTestCase { + + function testCurrentContextIsUnique() { + $this->assertSame( + SimpleTest::getContext(), + SimpleTest::getContext()); + } + + function testContextHoldsCurrentTestCase() { + $context = SimpleTest::getContext(); + $this->assertSame($this, $context->getTest()); + } + + function testResourceIsSingleInstanceWithContext() { + $context = new SimpleTestContext(); + $this->assertSame( + $context->get('DummyResource'), + $context->get('DummyResource')); + } + + function testClearingContextResetsResources() { + $context = new SimpleTestContext(); + $resource = $context->get('DummyResource'); + $context->clear(); + $this->assertClone($resource, $context->get('DummyResource')); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/site/file.html b/application/libraries/simpletest/test/site/file.html new file mode 100644 index 00000000000..cc41aee1b8b --- /dev/null +++ b/application/libraries/simpletest/test/site/file.html @@ -0,0 +1,6 @@ + + Link to SimpleTest + + Link to SimpleTest + + \ No newline at end of file diff --git a/application/libraries/simpletest/test/socket_test.php b/application/libraries/simpletest/test/socket_test.php new file mode 100644 index 00000000000..729adda4960 --- /dev/null +++ b/application/libraries/simpletest/test/socket_test.php @@ -0,0 +1,25 @@ +assertFalse($error->isError()); + $error->setError('Ouch'); + $this->assertTrue($error->isError()); + $this->assertEqual($error->getError(), 'Ouch'); + } + + function testClearingError() { + $error = new SimpleStickyError(); + $error->setError('Ouch'); + $this->assertTrue($error->isError()); + $error->clearError(); + $this->assertFalse($error->isError()); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/collector/collectable.1 b/application/libraries/simpletest/test/support/collector/collectable.1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/application/libraries/simpletest/test/support/collector/collectable.2 b/application/libraries/simpletest/test/support/collector/collectable.2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/application/libraries/simpletest/test/support/empty_test_file.php b/application/libraries/simpletest/test/support/empty_test_file.php new file mode 100644 index 00000000000..31e3f7bed62 --- /dev/null +++ b/application/libraries/simpletest/test/support/empty_test_file.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/failing_test.php b/application/libraries/simpletest/test/support/failing_test.php new file mode 100644 index 00000000000..30f0d7507d9 --- /dev/null +++ b/application/libraries/simpletest/test/support/failing_test.php @@ -0,0 +1,9 @@ +assertEqual(1,2); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/latin1_sample b/application/libraries/simpletest/test/support/latin1_sample new file mode 100644 index 00000000000..19035257766 --- /dev/null +++ b/application/libraries/simpletest/test/support/latin1_sample @@ -0,0 +1 @@ +£¹²³¼½¾@¶øþðßæ«»¢µ \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/passing_test.php b/application/libraries/simpletest/test/support/passing_test.php new file mode 100644 index 00000000000..b7863216353 --- /dev/null +++ b/application/libraries/simpletest/test/support/passing_test.php @@ -0,0 +1,9 @@ +assertEqual(2,2); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/spl_examples.php b/application/libraries/simpletest/test/support/spl_examples.php new file mode 100644 index 00000000000..45add356c44 --- /dev/null +++ b/application/libraries/simpletest/test/support/spl_examples.php @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/supplementary_upload_sample.txt b/application/libraries/simpletest/test/support/supplementary_upload_sample.txt new file mode 100644 index 00000000000..d8aa9e81013 --- /dev/null +++ b/application/libraries/simpletest/test/support/supplementary_upload_sample.txt @@ -0,0 +1 @@ +Some more text content \ No newline at end of file diff --git a/application/libraries/simpletest/test/support/test1.php b/application/libraries/simpletest/test/support/test1.php new file mode 100644 index 00000000000..b414586d642 --- /dev/null +++ b/application/libraries/simpletest/test/support/test1.php @@ -0,0 +1,7 @@ +assertEqual(3,1+2, "pass1"); + } +} +?> diff --git a/application/libraries/simpletest/test/support/upload_sample.txt b/application/libraries/simpletest/test/support/upload_sample.txt new file mode 100644 index 00000000000..ec98d7c5e3f --- /dev/null +++ b/application/libraries/simpletest/test/support/upload_sample.txt @@ -0,0 +1 @@ +Sample for testing file upload \ No newline at end of file diff --git a/application/libraries/simpletest/test/tag_test.php b/application/libraries/simpletest/test/tag_test.php new file mode 100644 index 00000000000..5e8a377f089 --- /dev/null +++ b/application/libraries/simpletest/test/tag_test.php @@ -0,0 +1,554 @@ + '1', 'b' => '')); + $this->assertEqual($tag->getTagName(), 'title'); + $this->assertIdentical($tag->getAttribute('a'), '1'); + $this->assertIdentical($tag->getAttribute('b'), ''); + $this->assertIdentical($tag->getAttribute('c'), false); + $this->assertIdentical($tag->getContent(), ''); + } + + function testTitleContent() { + $tag = new SimpleTitleTag(array()); + $this->assertTrue($tag->expectEndTag()); + $tag->addContent('Hello'); + $tag->addContent('World'); + $this->assertEqual($tag->getText(), 'HelloWorld'); + } + + function testMessyTitleContent() { + $tag = new SimpleTitleTag(array()); + $this->assertTrue($tag->expectEndTag()); + $tag->addContent('Hello'); + $tag->addContent('World'); + $this->assertEqual($tag->getText(), 'HelloWorld'); + } + + function testTagWithNoEnd() { + $tag = new SimpleTextTag(array()); + $this->assertFalse($tag->expectEndTag()); + } + + function testAnchorHref() { + $tag = new SimpleAnchorTag(array('href' => 'http://here/')); + $this->assertEqual($tag->getHref(), 'http://here/'); + + $tag = new SimpleAnchorTag(array('href' => '')); + $this->assertIdentical($tag->getAttribute('href'), ''); + $this->assertIdentical($tag->getHref(), ''); + + $tag = new SimpleAnchorTag(array()); + $this->assertIdentical($tag->getAttribute('href'), false); + $this->assertIdentical($tag->getHref(), ''); + } + + function testIsIdMatchesIdAttribute() { + $tag = new SimpleAnchorTag(array('href' => 'http://here/', 'id' => 7)); + $this->assertIdentical($tag->getAttribute('id'), '7'); + $this->assertTrue($tag->isId(7)); + } +} + +class TestOfWidget extends UnitTestCase { + + function testTextEmptyDefault() { + $tag = new SimpleTextTag(array('type' => 'text')); + $this->assertIdentical($tag->getDefault(), ''); + $this->assertIdentical($tag->getValue(), ''); + } + + function testSettingOfExternalLabel() { + $tag = new SimpleTextTag(array('type' => 'text')); + $tag->setLabel('it'); + $this->assertTrue($tag->isLabel('it')); + } + + function testTextDefault() { + $tag = new SimpleTextTag(array('value' => 'aaa')); + $this->assertEqual($tag->getDefault(), 'aaa'); + $this->assertEqual($tag->getValue(), 'aaa'); + } + + function testSettingTextValue() { + $tag = new SimpleTextTag(array('value' => 'aaa')); + $tag->setValue('bbb'); + $this->assertEqual($tag->getValue(), 'bbb'); + $tag->resetValue(); + $this->assertEqual($tag->getValue(), 'aaa'); + } + + function testFailToSetHiddenValue() { + $tag = new SimpleTextTag(array('value' => 'aaa', 'type' => 'hidden')); + $this->assertFalse($tag->setValue('bbb')); + $this->assertEqual($tag->getValue(), 'aaa'); + } + + function testSubmitDefaults() { + $tag = new SimpleSubmitTag(array('type' => 'submit')); + $this->assertIdentical($tag->getName(), false); + $this->assertEqual($tag->getValue(), 'Submit'); + $this->assertFalse($tag->setValue('Cannot set this')); + $this->assertEqual($tag->getValue(), 'Submit'); + $this->assertEqual($tag->getLabel(), 'Submit'); + + $encoding = new MockSimpleMultipartEncoding(); + $encoding->expectNever('add'); + $tag->write($encoding); + } + + function testPopulatedSubmit() { + $tag = new SimpleSubmitTag( + array('type' => 'submit', 'name' => 's', 'value' => 'Ok!')); + $this->assertEqual($tag->getName(), 's'); + $this->assertEqual($tag->getValue(), 'Ok!'); + $this->assertEqual($tag->getLabel(), 'Ok!'); + + $encoding = new MockSimpleMultipartEncoding(); + $encoding->expectOnce('add', array('s', 'Ok!')); + $tag->write($encoding); + } + + function testImageSubmit() { + $tag = new SimpleImageSubmitTag( + array('type' => 'image', 'name' => 's', 'alt' => 'Label')); + $this->assertEqual($tag->getName(), 's'); + $this->assertEqual($tag->getLabel(), 'Label'); + + $encoding = new MockSimpleMultipartEncoding(); + $encoding->expectAt(0, 'add', array('s.x', 20)); + $encoding->expectAt(1, 'add', array('s.y', 30)); + $tag->write($encoding, 20, 30); + } + + function testImageSubmitTitlePreferredOverAltForLabel() { + $tag = new SimpleImageSubmitTag( + array('type' => 'image', 'name' => 's', 'alt' => 'Label', 'title' => 'Title')); + $this->assertEqual($tag->getLabel(), 'Title'); + } + + function testButton() { + $tag = new SimpleButtonTag( + array('type' => 'submit', 'name' => 's', 'value' => 'do')); + $tag->addContent('I am a button'); + $this->assertEqual($tag->getName(), 's'); + $this->assertEqual($tag->getValue(), 'do'); + $this->assertEqual($tag->getLabel(), 'I am a button'); + + $encoding = new MockSimpleMultipartEncoding(); + $encoding->expectOnce('add', array('s', 'do')); + $tag->write($encoding); + } +} + +class TestOfTextArea extends UnitTestCase { + + function testDefault() { + $tag = new SimpleTextAreaTag(array('name' => 'a')); + $tag->addContent('Some text'); + $this->assertEqual($tag->getName(), 'a'); + $this->assertEqual($tag->getDefault(), 'Some text'); + } + + function testWrapping() { + $tag = new SimpleTextAreaTag(array('cols' => '10', 'wrap' => 'physical')); + $tag->addContent("Lot's of text that should be wrapped"); + $this->assertEqual( + $tag->getDefault(), + "Lot's of\r\ntext that\r\nshould be\r\nwrapped"); + $tag->setValue("New long text\r\nwith two lines"); + $this->assertEqual( + $tag->getValue(), + "New long\r\ntext\r\nwith two\r\nlines"); + } + + function testWrappingRemovesLeadingcariageReturn() { + $tag = new SimpleTextAreaTag(array('cols' => '20', 'wrap' => 'physical')); + $tag->addContent("\rStuff"); + $this->assertEqual($tag->getDefault(), 'Stuff'); + $tag->setValue("\nNew stuff\n"); + $this->assertEqual($tag->getValue(), "New stuff\r\n"); + } + + function testBreaksAreNewlineAndCarriageReturn() { + $tag = new SimpleTextAreaTag(array('cols' => '10')); + $tag->addContent("Some\nText\rwith\r\nbreaks"); + $this->assertEqual($tag->getValue(), "Some\r\nText\r\nwith\r\nbreaks"); + } +} + +class TestOfCheckbox extends UnitTestCase { + + function testCanSetCheckboxToNamedValueWithBooleanTrue() { + $tag = new SimpleCheckboxTag(array('name' => 'a', 'value' => 'A')); + $this->assertEqual($tag->getValue(), false); + $tag->setValue(true); + $this->assertIdentical($tag->getValue(), 'A'); + } +} + +class TestOfSelection extends UnitTestCase { + + function testEmpty() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $this->assertIdentical($tag->getValue(), ''); + } + + function testSingle() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $option = new SimpleOptionTag(array()); + $option->addContent('AAA'); + $tag->addTag($option); + $this->assertEqual($tag->getValue(), 'AAA'); + } + + function testSingleDefault() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $option = new SimpleOptionTag(array('selected' => '')); + $option->addContent('AAA'); + $tag->addTag($option); + $this->assertEqual($tag->getValue(), 'AAA'); + } + + function testSingleMappedDefault() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $option = new SimpleOptionTag(array('selected' => '', 'value' => 'aaa')); + $option->addContent('AAA'); + $tag->addTag($option); + $this->assertEqual($tag->getValue(), 'aaa'); + } + + function testStartsWithDefault() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array()); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('selected' => '')); + $b->addContent('BBB'); + $tag->addTag($b); + $c = new SimpleOptionTag(array()); + $c->addContent('CCC'); + $tag->addTag($c); + $this->assertEqual($tag->getValue(), 'BBB'); + } + + function testSettingOption() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array()); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('selected' => '')); + $b->addContent('BBB'); + $tag->addTag($b); + $c = new SimpleOptionTag(array()); + $c->addContent('CCC'); + $tag->setValue('AAA'); + $this->assertEqual($tag->getValue(), 'AAA'); + } + + function testSettingMappedOption() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array('value' => 'aaa')); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('value' => 'bbb', 'selected' => '')); + $b->addContent('BBB'); + $tag->addTag($b); + $c = new SimpleOptionTag(array('value' => 'ccc')); + $c->addContent('CCC'); + $tag->addTag($c); + $tag->setValue('AAA'); + $this->assertEqual($tag->getValue(), 'aaa'); + $tag->setValue('ccc'); + $this->assertEqual($tag->getValue(), 'ccc'); + } + + function testSelectionDespiteSpuriousWhitespace() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array()); + $a->addContent(' AAA '); + $tag->addTag($a); + $b = new SimpleOptionTag(array('selected' => '')); + $b->addContent(' BBB '); + $tag->addTag($b); + $c = new SimpleOptionTag(array()); + $c->addContent(' CCC '); + $tag->addTag($c); + $this->assertEqual($tag->getValue(), ' BBB '); + $tag->setValue('AAA'); + $this->assertEqual($tag->getValue(), ' AAA '); + } + + function testFailToSetIllegalOption() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array()); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('selected' => '')); + $b->addContent('BBB'); + $tag->addTag($b); + $c = new SimpleOptionTag(array()); + $c->addContent('CCC'); + $tag->addTag($c); + $this->assertFalse($tag->setValue('Not present')); + $this->assertEqual($tag->getValue(), 'BBB'); + } + + function testNastyOptionValuesThatLookLikeFalse() { + $tag = new SimpleSelectionTag(array('name' => 'a')); + $a = new SimpleOptionTag(array('value' => '1')); + $a->addContent('One'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('value' => '0')); + $b->addContent('Zero'); + $tag->addTag($b); + $this->assertIdentical($tag->getValue(), '1'); + $tag->setValue('Zero'); + $this->assertIdentical($tag->getValue(), '0'); + } + + function testBlankOption() { + $tag = new SimpleSelectionTag(array('name' => 'A')); + $a = new SimpleOptionTag(array()); + $tag->addTag($a); + $b = new SimpleOptionTag(array()); + $b->addContent('b'); + $tag->addTag($b); + $this->assertIdentical($tag->getValue(), ''); + $tag->setValue('b'); + $this->assertIdentical($tag->getValue(), 'b'); + $tag->setValue(''); + $this->assertIdentical($tag->getValue(), ''); + } + + function testMultipleDefaultWithNoSelections() { + $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); + $a = new SimpleOptionTag(array()); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array()); + $b->addContent('BBB'); + $tag->addTag($b); + $this->assertIdentical($tag->getDefault(), array()); + $this->assertIdentical($tag->getValue(), array()); + } + + function testMultipleDefaultWithSelections() { + $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); + $a = new SimpleOptionTag(array('selected' => '')); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array('selected' => '')); + $b->addContent('BBB'); + $tag->addTag($b); + $this->assertIdentical($tag->getDefault(), array('AAA', 'BBB')); + $this->assertIdentical($tag->getValue(), array('AAA', 'BBB')); + } + + function testSettingMultiple() { + $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); + $a = new SimpleOptionTag(array('selected' => '')); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array()); + $b->addContent('BBB'); + $tag->addTag($b); + $c = new SimpleOptionTag(array('selected' => '', 'value' => 'ccc')); + $c->addContent('CCC'); + $tag->addTag($c); + $this->assertIdentical($tag->getDefault(), array('AAA', 'ccc')); + $this->assertTrue($tag->setValue(array('BBB', 'ccc'))); + $this->assertIdentical($tag->getValue(), array('BBB', 'ccc')); + $this->assertTrue($tag->setValue(array())); + $this->assertIdentical($tag->getValue(), array()); + } + + function testFailToSetIllegalOptionsInMultiple() { + $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => '')); + $a = new SimpleOptionTag(array('selected' => '')); + $a->addContent('AAA'); + $tag->addTag($a); + $b = new SimpleOptionTag(array()); + $b->addContent('BBB'); + $tag->addTag($b); + $this->assertFalse($tag->setValue(array('CCC'))); + $this->assertTrue($tag->setValue(array('AAA', 'BBB'))); + $this->assertFalse($tag->setValue(array('AAA', 'CCC'))); + } +} + +class TestOfRadioGroup extends UnitTestCase { + + function testEmptyGroup() { + $group = new SimpleRadioGroup(); + $this->assertIdentical($group->getDefault(), false); + $this->assertIdentical($group->getValue(), false); + $this->assertFalse($group->setValue('a')); + } + + function testReadingSingleButtonGroup() { + $group = new SimpleRadioGroup(); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'A', 'checked' => ''))); + $this->assertIdentical($group->getDefault(), 'A'); + $this->assertIdentical($group->getValue(), 'A'); + } + + function testReadingMultipleButtonGroup() { + $group = new SimpleRadioGroup(); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'A'))); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'B', 'checked' => ''))); + $this->assertIdentical($group->getDefault(), 'B'); + $this->assertIdentical($group->getValue(), 'B'); + } + + function testFailToSetUnlistedValue() { + $group = new SimpleRadioGroup(); + $group->addWidget(new SimpleRadioButtonTag(array('value' => 'z'))); + $this->assertFalse($group->setValue('a')); + $this->assertIdentical($group->getValue(), false); + } + + function testSettingNewValueClearsTheOldOne() { + $group = new SimpleRadioGroup(); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'A'))); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'B', 'checked' => ''))); + $this->assertTrue($group->setValue('A')); + $this->assertIdentical($group->getValue(), 'A'); + } + + function testIsIdMatchesAnyWidgetInSet() { + $group = new SimpleRadioGroup(); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'A', 'id' => 'i1'))); + $group->addWidget(new SimpleRadioButtonTag( + array('value' => 'B', 'id' => 'i2'))); + $this->assertFalse($group->isId('i0')); + $this->assertTrue($group->isId('i1')); + $this->assertTrue($group->isId('i2')); + } + + function testIsLabelMatchesAnyWidgetInSet() { + $group = new SimpleRadioGroup(); + $button1 = new SimpleRadioButtonTag(array('value' => 'A')); + $button1->setLabel('one'); + $group->addWidget($button1); + $button2 = new SimpleRadioButtonTag(array('value' => 'B')); + $button2->setLabel('two'); + $group->addWidget($button2); + $this->assertFalse($group->isLabel('three')); + $this->assertTrue($group->isLabel('one')); + $this->assertTrue($group->isLabel('two')); + } +} + +class TestOfTagGroup extends UnitTestCase { + + function testReadingMultipleCheckboxGroup() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag( + array('value' => 'B', 'checked' => ''))); + $this->assertIdentical($group->getDefault(), 'B'); + $this->assertIdentical($group->getValue(), 'B'); + } + + function testReadingMultipleUncheckedItems() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); + $this->assertIdentical($group->getDefault(), false); + $this->assertIdentical($group->getValue(), false); + } + + function testReadingMultipleCheckedItems() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag( + array('value' => 'A', 'checked' => ''))); + $group->addWidget(new SimpleCheckboxTag( + array('value' => 'B', 'checked' => ''))); + $this->assertIdentical($group->getDefault(), array('A', 'B')); + $this->assertIdentical($group->getValue(), array('A', 'B')); + } + + function testSettingSingleValue() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); + $this->assertTrue($group->setValue('A')); + $this->assertIdentical($group->getValue(), 'A'); + $this->assertTrue($group->setValue('B')); + $this->assertIdentical($group->getValue(), 'B'); + } + + function testSettingMultipleValues() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); + $this->assertTrue($group->setValue(array('A', 'B'))); + $this->assertIdentical($group->getValue(), array('A', 'B')); + } + + function testSettingNoValue() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag(array('value' => 'B'))); + $this->assertTrue($group->setValue(false)); + $this->assertIdentical($group->getValue(), false); + } + + function testIsIdMatchesAnyIdInSet() { + $group = new SimpleCheckboxGroup(); + $group->addWidget(new SimpleCheckboxTag(array('id' => 1, 'value' => 'A'))); + $group->addWidget(new SimpleCheckboxTag(array('id' => 2, 'value' => 'B'))); + $this->assertFalse($group->isId(0)); + $this->assertTrue($group->isId(1)); + $this->assertTrue($group->isId(2)); + } +} + +class TestOfUploadWidget extends UnitTestCase { + + function testValueIsFilePath() { + $upload = new SimpleUploadTag(array('name' => 'a')); + $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt'); + $this->assertEqual($upload->getValue(), dirname(__FILE__) . '/support/upload_sample.txt'); + } + + function testSubmitsFileContents() { + $encoding = new MockSimpleMultipartEncoding(); + $encoding->expectOnce('attach', array( + 'a', + 'Sample for testing file upload', + 'upload_sample.txt')); + $upload = new SimpleUploadTag(array('name' => 'a')); + $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt'); + $upload->write($encoding); + } +} + +class TestOfLabelTag extends UnitTestCase { + + function testLabelShouldHaveAnEndTag() { + $label = new SimpleLabelTag(array()); + $this->assertTrue($label->expectEndTag()); + } + + function testContentIsTextOnly() { + $label = new SimpleLabelTag(array()); + $label->addContent('Here are words'); + $this->assertEqual($label->getText(), 'Here are words'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/test_with_parse_error.php b/application/libraries/simpletest/test/test_with_parse_error.php new file mode 100644 index 00000000000..41a5832a5cb --- /dev/null +++ b/application/libraries/simpletest/test/test_with_parse_error.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/application/libraries/simpletest/test/unit_tester_test.php b/application/libraries/simpletest/test/unit_tester_test.php new file mode 100644 index 00000000000..ce9850f09ab --- /dev/null +++ b/application/libraries/simpletest/test/unit_tester_test.php @@ -0,0 +1,61 @@ +assertTrue($this->assertTrue(true)); + } + + function testAssertFalseReturnsAssertionAsBoolean() { + $this->assertTrue($this->assertFalse(false)); + } + + function testAssertEqualReturnsAssertionAsBoolean() { + $this->assertTrue($this->assertEqual(5, 5)); + } + + function testAssertIdenticalReturnsAssertionAsBoolean() { + $this->assertTrue($this->assertIdentical(5, 5)); + } + + function testCoreAssertionsDoNotThrowErrors() { + $this->assertIsA($this, 'UnitTestCase'); + $this->assertNotA($this, 'WebTestCase'); + } + + function testReferenceAssertionOnObjects() { + $a = new ReferenceForTesting(); + $b = $a; + $this->assertSame($a, $b); + } + + function testReferenceAssertionOnScalars() { + $a = 25; + $b = &$a; + $this->assertReference($a, $b); + } + + function testCloneOnObjects() { + $a = new ReferenceForTesting(); + $b = new ReferenceForTesting(); + $this->assertClone($a, $b); + } + + function TODO_testCloneOnScalars() { + $a = 25; + $b = 25; + $this->assertClone($a, $b); + } + + function testCopyOnScalars() { + $a = 25; + $b = 25; + $this->assertCopy($a, $b); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/unit_tests.php b/application/libraries/simpletest/test/unit_tests.php new file mode 100644 index 00000000000..9e621293f9e --- /dev/null +++ b/application/libraries/simpletest/test/unit_tests.php @@ -0,0 +1,49 @@ +TestSuite('Unit tests'); + $path = dirname(__FILE__); + $this->addFile($path . '/errors_test.php'); + $this->addFile($path . '/exceptions_test.php'); + $this->addFile($path . '/arguments_test.php'); + $this->addFile($path . '/autorun_test.php'); + $this->addFile($path . '/compatibility_test.php'); + $this->addFile($path . '/simpletest_test.php'); + $this->addFile($path . '/dumper_test.php'); + $this->addFile($path . '/expectation_test.php'); + $this->addFile($path . '/unit_tester_test.php'); + $this->addFile($path . '/reflection_php5_test.php'); + $this->addFile($path . '/mock_objects_test.php'); + $this->addFile($path . '/interfaces_test.php'); + $this->addFile($path . '/collector_test.php'); + $this->addFile($path . '/recorder_test.php'); + $this->addFile($path . '/adapter_test.php'); + $this->addFile($path . '/socket_test.php'); + $this->addFile($path . '/encoding_test.php'); + $this->addFile($path . '/url_test.php'); + $this->addFile($path . '/cookies_test.php'); + $this->addFile($path . '/http_test.php'); + $this->addFile($path . '/authentication_test.php'); + $this->addFile($path . '/user_agent_test.php'); + $this->addFile($path . '/php_parser_test.php'); + $this->addFile($path . '/parsing_test.php'); + $this->addFile($path . '/tag_test.php'); + $this->addFile($path . '/form_test.php'); + $this->addFile($path . '/page_test.php'); + $this->addFile($path . '/frames_test.php'); + $this->addFile($path . '/browser_test.php'); + $this->addFile($path . '/web_tester_test.php'); + $this->addFile($path . '/shell_tester_test.php'); + $this->addFile($path . '/xml_test.php'); + $this->addFile($path . '/../extensions/testdox/test.php'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/url_test.php b/application/libraries/simpletest/test/url_test.php new file mode 100644 index 00000000000..80119afbdde --- /dev/null +++ b/application/libraries/simpletest/test/url_test.php @@ -0,0 +1,515 @@ +assertEqual($url->getScheme(), ''); + $this->assertEqual($url->getHost(), ''); + $this->assertEqual($url->getScheme('http'), 'http'); + $this->assertEqual($url->getHost('localhost'), 'localhost'); + $this->assertEqual($url->getPath(), ''); + } + + function testBasicParsing() { + $url = new SimpleUrl('https://www.lastcraft.com/test/'); + $this->assertEqual($url->getScheme(), 'https'); + $this->assertEqual($url->getHost(), 'www.lastcraft.com'); + $this->assertEqual($url->getPath(), '/test/'); + } + + function testRelativeUrls() { + $url = new SimpleUrl('../somewhere.php'); + $this->assertEqual($url->getScheme(), false); + $this->assertEqual($url->getHost(), false); + $this->assertEqual($url->getPath(), '../somewhere.php'); + } + + function testParseBareParameter() { + $url = new SimpleUrl('?a'); + $this->assertEqual($url->getPath(), ''); + $this->assertEqual($url->getEncodedRequest(), '?a'); + $url->addRequestParameter('x', 'X'); + $this->assertEqual($url->getEncodedRequest(), '?a=&x=X'); + } + + function testParseEmptyParameter() { + $url = new SimpleUrl('?a='); + $this->assertEqual($url->getPath(), ''); + $this->assertEqual($url->getEncodedRequest(), '?a='); + $url->addRequestParameter('x', 'X'); + $this->assertEqual($url->getEncodedRequest(), '?a=&x=X'); + } + + function testParseParameterPair() { + $url = new SimpleUrl('?a=A'); + $this->assertEqual($url->getPath(), ''); + $this->assertEqual($url->getEncodedRequest(), '?a=A'); + $url->addRequestParameter('x', 'X'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&x=X'); + } + + function testParseMultipleParameters() { + $url = new SimpleUrl('?a=A&b=B'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B'); + $url->addRequestParameter('x', 'X'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&x=X'); + } + + function testParsingParameterMixture() { + $url = new SimpleUrl('?a=A&b=&c'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c'); + $url->addRequestParameter('x', 'X'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c=&x=X'); + } + + function testAddParametersFromScratch() { + $url = new SimpleUrl(''); + $url->addRequestParameter('a', 'A'); + $this->assertEqual($url->getEncodedRequest(), '?a=A'); + $url->addRequestParameter('b', 'B'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B'); + $url->addRequestParameter('a', 'aaa'); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&a=aaa'); + } + + function testClearingParameters() { + $url = new SimpleUrl(''); + $url->addRequestParameter('a', 'A'); + $url->clearRequest(); + $this->assertIdentical($url->getEncodedRequest(), ''); + } + + function testEncodingParameters() { + $url = new SimpleUrl(''); + $url->addRequestParameter('a', '?!"\'#~@[]{}:;<>,./|$%^&*()_+-='); + $this->assertIdentical( + $request = $url->getEncodedRequest(), + '?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%24%25%5E%26%2A%28%29_%2B-%3D'); + } + + function testDecodingParameters() { + $url = new SimpleUrl('?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%24%25%5E%26%2A%28%29_%2B-%3D'); + $this->assertEqual( + $url->getEncodedRequest(), + '?a=' . urlencode('?!"\'#~@[]{}:;<>,./|$%^&*()_+-=')); + } + + function testUrlInQueryDoesNotConfuseParsing() { + $url = new SimpleUrl('wibble/login.php?url=http://www.google.com/moo/'); + $this->assertFalse($url->getScheme()); + $this->assertFalse($url->getHost()); + $this->assertEqual($url->getPath(), 'wibble/login.php'); + $this->assertEqual($url->getEncodedRequest(), '?url=http://www.google.com/moo/'); + } + + function testSettingCordinates() { + $url = new SimpleUrl(''); + $url->setCoordinates('32', '45'); + $this->assertIdentical($url->getX(), 32); + $this->assertIdentical($url->getY(), 45); + $this->assertEqual($url->getEncodedRequest(), ''); + } + + function testParseCordinates() { + $url = new SimpleUrl('?32,45'); + $this->assertIdentical($url->getX(), 32); + $this->assertIdentical($url->getY(), 45); + } + + function testClearingCordinates() { + $url = new SimpleUrl('?32,45'); + $url->setCoordinates(); + $this->assertIdentical($url->getX(), false); + $this->assertIdentical($url->getY(), false); + } + + function testParsingParameterCordinateMixture() { + $url = new SimpleUrl('?a=A&b=&c?32,45'); + $this->assertIdentical($url->getX(), 32); + $this->assertIdentical($url->getY(), 45); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c'); + } + + function testParsingParameterWithBadCordinates() { + $url = new SimpleUrl('?a=A&b=&c?32'); + $this->assertIdentical($url->getX(), false); + $this->assertIdentical($url->getY(), false); + $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c?32'); + } + + function testPageSplitting() { + $url = new SimpleUrl('./here/../there/somewhere.php'); + $this->assertEqual($url->getPath(), './here/../there/somewhere.php'); + $this->assertEqual($url->getPage(), 'somewhere.php'); + $this->assertEqual($url->getBasePath(), './here/../there/'); + } + + function testAbsolutePathPageSplitting() { + $url = new SimpleUrl("http://host.com/here/there/somewhere.php"); + $this->assertEqual($url->getPath(), "/here/there/somewhere.php"); + $this->assertEqual($url->getPage(), "somewhere.php"); + $this->assertEqual($url->getBasePath(), "/here/there/"); + } + + function testSplittingUrlWithNoPageGivesEmptyPage() { + $url = new SimpleUrl('/here/there/'); + $this->assertEqual($url->getPath(), '/here/there/'); + $this->assertEqual($url->getPage(), ''); + $this->assertEqual($url->getBasePath(), '/here/there/'); + } + + function testPathNormalisation() { + $url = new SimpleUrl(); + $this->assertEqual( + $url->normalisePath('https://host.com/I/am/here/../there/somewhere.php'), + 'https://host.com/I/am/there/somewhere.php'); + } + + // regression test for #1535407 + function testPathNormalisationWithSinglePeriod() { + $url = new SimpleUrl(); + $this->assertEqual( + $url->normalisePath('https://host.com/I/am/here/./../there/somewhere.php'), + 'https://host.com/I/am/there/somewhere.php'); + } + + // regression test for #1852413 + function testHostnameExtractedFromUContainingAtSign() { + $url = new SimpleUrl("http://localhost/name@example.com"); + $this->assertEqual($url->getScheme(), "http"); + $this->assertEqual($url->getUsername(), ""); + $this->assertEqual($url->getPassword(), ""); + $this->assertEqual($url->getHost(), "localhost"); + $this->assertEqual($url->getPath(), "/name@example.com"); + } + + function testHostnameInLocalhost() { + $url = new SimpleUrl("http://localhost/name/example.com"); + $this->assertEqual($url->getScheme(), "http"); + $this->assertEqual($url->getUsername(), ""); + $this->assertEqual($url->getPassword(), ""); + $this->assertEqual($url->getHost(), "localhost"); + $this->assertEqual($url->getPath(), "/name/example.com"); + } + + function testUsernameAndPasswordAreUrlDecoded() { + $url = new SimpleUrl('http://' . urlencode('test@test') . + ':' . urlencode('$!�@*&%') . '@www.lastcraft.com'); + $this->assertEqual($url->getUsername(), 'test@test'); + $this->assertEqual($url->getPassword(), '$!�@*&%'); + } + + function testBlitz() { + $this->assertUrl( + "https://username:password@www.somewhere.com:243/this/that/here.php?a=1&b=2#anchor", + array("https", "username", "password", "www.somewhere.com", 243, "/this/that/here.php", "com", "?a=1&b=2", "anchor"), + array("a" => "1", "b" => "2")); + $this->assertUrl( + "username:password@www.somewhere.com/this/that/here.php?a=1", + array(false, "username", "password", "www.somewhere.com", false, "/this/that/here.php", "com", "?a=1", false), + array("a" => "1")); + $this->assertUrl( + "username:password@somewhere.com:243?1,2", + array(false, "username", "password", "somewhere.com", 243, "/", "com", "", false), + array(), + array(1, 2)); + $this->assertUrl( + "https://www.somewhere.com", + array("https", false, false, "www.somewhere.com", false, "/", "com", "", false)); + $this->assertUrl( + "username@www.somewhere.com:243#anchor", + array(false, "username", false, "www.somewhere.com", 243, "/", "com", "", "anchor")); + $this->assertUrl( + "/this/that/here.php?a=1&b=2?3,4", + array(false, false, false, false, false, "/this/that/here.php", false, "?a=1&b=2", false), + array("a" => "1", "b" => "2"), + array(3, 4)); + $this->assertUrl( + "username@/here.php?a=1&b=2", + array(false, "username", false, false, false, "/here.php", false, "?a=1&b=2", false), + array("a" => "1", "b" => "2")); + } + + function testAmbiguousHosts() { + $this->assertUrl( + "tigger", + array(false, false, false, false, false, "tigger", false, "", false)); + $this->assertUrl( + "/tigger", + array(false, false, false, false, false, "/tigger", false, "", false)); + $this->assertUrl( + "//tigger", + array(false, false, false, "tigger", false, "/", false, "", false)); + $this->assertUrl( + "//tigger/", + array(false, false, false, "tigger", false, "/", false, "", false)); + $this->assertUrl( + "tigger.com", + array(false, false, false, "tigger.com", false, "/", "com", "", false)); + $this->assertUrl( + "me.net/tigger", + array(false, false, false, "me.net", false, "/tigger", "net", "", false)); + } + + function testAsString() { + $this->assertPreserved('https://www.here.com'); + $this->assertPreserved('http://me:secret@www.here.com'); + $this->assertPreserved('http://here/there'); + $this->assertPreserved('http://here/there?a=A&b=B'); + $this->assertPreserved('http://here/there?a=1&a=2'); + $this->assertPreserved('http://here/there?a=1&a=2?9,8'); + $this->assertPreserved('http://host?a=1&a=2'); + $this->assertPreserved('http://host#stuff'); + $this->assertPreserved('http://me:secret@www.here.com/a/b/c/here.html?a=A?7,6'); + $this->assertPreserved('http://www.here.com/?a=A__b=B'); + $this->assertPreserved('http://www.example.com:8080/'); + } + + function testUrlWithTwoSlashesInPath() { + $url = new SimpleUrl('/article/categoryedit/insert//'); + $this->assertEqual($url->getPath(), '/article/categoryedit/insert//'); + } + + function testUrlWithRequestKeyEncoded() { + $url = new SimpleUrl('/?foo%5B1%5D=bar'); + $this->assertEqual($url->getEncodedRequest(), '?foo%5B1%5D=bar'); + $url->addRequestParameter('a[1]', 'b[]'); + $this->assertEqual($url->getEncodedRequest(), '?foo%5B1%5D=bar&a%5B1%5D=b%5B%5D'); + + $url = new SimpleUrl('/'); + $url->addRequestParameter('a[1]', 'b[]'); + $this->assertEqual($url->getEncodedRequest(), '?a%5B1%5D=b%5B%5D'); + } + + function testUrlWithRequestKeyEncodedAndParamNamLookingLikePair() { + $url = new SimpleUrl('/'); + $url->addRequestParameter('foo[]=bar', ''); + $this->assertEqual($url->getEncodedRequest(), '?foo%5B%5D%3Dbar='); + $url = new SimpleUrl('/?foo%5B%5D%3Dbar='); + $this->assertEqual($url->getEncodedRequest(), '?foo%5B%5D%3Dbar='); + } + + function assertUrl($raw, $parts, $params = false, $coords = false) { + if (! is_array($params)) { + $params = array(); + } + $url = new SimpleUrl($raw); + $this->assertIdentical($url->getScheme(), $parts[0], "[$raw] scheme -> %s"); + $this->assertIdentical($url->getUsername(), $parts[1], "[$raw] username -> %s"); + $this->assertIdentical($url->getPassword(), $parts[2], "[$raw] password -> %s"); + $this->assertIdentical($url->getHost(), $parts[3], "[$raw] host -> %s"); + $this->assertIdentical($url->getPort(), $parts[4], "[$raw] port -> %s"); + $this->assertIdentical($url->getPath(), $parts[5], "[$raw] path -> %s"); + $this->assertIdentical($url->getTld(), $parts[6], "[$raw] tld -> %s"); + $this->assertIdentical($url->getEncodedRequest(), $parts[7], "[$raw] encoded -> %s"); + $this->assertIdentical($url->getFragment(), $parts[8], "[$raw] fragment -> %s"); + if ($coords) { + $this->assertIdentical($url->getX(), $coords[0], "[$raw] x -> %s"); + $this->assertIdentical($url->getY(), $coords[1], "[$raw] y -> %s"); + } + } + + function assertPreserved($string) { + $url = new SimpleUrl($string); + $this->assertEqual($url->asString(), $string); + } +} + +class TestOfAbsoluteUrls extends UnitTestCase { + + function testDirectoriesAfterFilename() { + $string = '../../index.php/foo/bar'; + $url = new SimpleUrl($string); + $this->assertEqual($url->asString(), $string); + + $absolute = $url->makeAbsolute('http://www.domain.com/some/path/'); + $this->assertEqual($absolute->asString(), 'http://www.domain.com/index.php/foo/bar'); + } + + function testMakingAbsolute() { + $url = new SimpleUrl('../there/somewhere.php'); + $this->assertEqual($url->getPath(), '../there/somewhere.php'); + $absolute = $url->makeAbsolute('https://host.com:1234/I/am/here/'); + $this->assertEqual($absolute->getScheme(), 'https'); + $this->assertEqual($absolute->getHost(), 'host.com'); + $this->assertEqual($absolute->getPort(), 1234); + $this->assertEqual($absolute->getPath(), '/I/am/there/somewhere.php'); + } + + function testMakingAnEmptyUrlAbsolute() { + $url = new SimpleUrl(''); + $this->assertEqual($url->getPath(), ''); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); + $this->assertEqual($absolute->getScheme(), 'http'); + $this->assertEqual($absolute->getHost(), 'host.com'); + $this->assertEqual($absolute->getPath(), '/I/am/here/page.html'); + } + + function testMakingAnEmptyUrlAbsoluteWithMissingPageName() { + $url = new SimpleUrl(''); + $this->assertEqual($url->getPath(), ''); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); + $this->assertEqual($absolute->getScheme(), 'http'); + $this->assertEqual($absolute->getHost(), 'host.com'); + $this->assertEqual($absolute->getPath(), '/I/am/here/'); + } + + function testMakingAShortQueryUrlAbsolute() { + $url = new SimpleUrl('?a#b'); + $this->assertEqual($url->getPath(), ''); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); + $this->assertEqual($absolute->getScheme(), 'http'); + $this->assertEqual($absolute->getHost(), 'host.com'); + $this->assertEqual($absolute->getPath(), '/I/am/here/'); + $this->assertEqual($absolute->getEncodedRequest(), '?a'); + $this->assertEqual($absolute->getFragment(), 'b'); + } + + function testMakingADirectoryUrlAbsolute() { + $url = new SimpleUrl('hello/'); + $this->assertEqual($url->getPath(), 'hello/'); + $this->assertEqual($url->getBasePath(), 'hello/'); + $this->assertEqual($url->getPage(), ''); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); + $this->assertEqual($absolute->getPath(), '/I/am/here/hello/'); + } + + function testMakingARootUrlAbsolute() { + $url = new SimpleUrl('/'); + $this->assertEqual($url->getPath(), '/'); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); + $this->assertEqual($absolute->getPath(), '/'); + } + + function testMakingARootPageUrlAbsolute() { + $url = new SimpleUrl('/here.html'); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html'); + $this->assertEqual($absolute->getPath(), '/here.html'); + } + + function testCarryAuthenticationFromRootPage() { + $url = new SimpleUrl('here.html'); + $absolute = $url->makeAbsolute('http://test:secret@host.com/'); + $this->assertEqual($absolute->getPath(), '/here.html'); + $this->assertEqual($absolute->getUsername(), 'test'); + $this->assertEqual($absolute->getPassword(), 'secret'); + } + + function testMakingCoordinateUrlAbsolute() { + $url = new SimpleUrl('?1,2'); + $this->assertEqual($url->getPath(), ''); + $absolute = $url->makeAbsolute('http://host.com/I/am/here/'); + $this->assertEqual($absolute->getScheme(), 'http'); + $this->assertEqual($absolute->getHost(), 'host.com'); + $this->assertEqual($absolute->getPath(), '/I/am/here/'); + $this->assertEqual($absolute->getX(), 1); + $this->assertEqual($absolute->getY(), 2); + } + + function testMakingAbsoluteAppendedPath() { + $url = new SimpleUrl('./there/somewhere.php'); + $absolute = $url->makeAbsolute('https://host.com/here/'); + $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php'); + } + + function testMakingAbsoluteBadlyFormedAppendedPath() { + $url = new SimpleUrl('there/somewhere.php'); + $absolute = $url->makeAbsolute('https://host.com/here/'); + $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php'); + } + + function testMakingAbsoluteHasNoEffectWhenAlreadyAbsolute() { + $url = new SimpleUrl('https://test:secret@www.lastcraft.com:321/stuff/?a=1#f'); + $absolute = $url->makeAbsolute('http://host.com/here/'); + $this->assertEqual($absolute->getScheme(), 'https'); + $this->assertEqual($absolute->getUsername(), 'test'); + $this->assertEqual($absolute->getPassword(), 'secret'); + $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); + $this->assertEqual($absolute->getPort(), 321); + $this->assertEqual($absolute->getPath(), '/stuff/'); + $this->assertEqual($absolute->getEncodedRequest(), '?a=1'); + $this->assertEqual($absolute->getFragment(), 'f'); + } + + function testMakingAbsoluteCarriesAuthenticationWhenAlreadyAbsolute() { + $url = new SimpleUrl('https://www.lastcraft.com'); + $absolute = $url->makeAbsolute('http://test:secret@host.com/here/'); + $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); + $this->assertEqual($absolute->getUsername(), 'test'); + $this->assertEqual($absolute->getPassword(), 'secret'); + } + + function testMakingHostOnlyAbsoluteDoesNotCarryAnyOtherInformation() { + $url = new SimpleUrl('http://www.lastcraft.com'); + $absolute = $url->makeAbsolute('https://host.com:81/here/'); + $this->assertEqual($absolute->getScheme(), 'http'); + $this->assertEqual($absolute->getHost(), 'www.lastcraft.com'); + $this->assertIdentical($absolute->getPort(), false); + $this->assertEqual($absolute->getPath(), '/'); + } +} + +class TestOfFrameUrl extends UnitTestCase { + + function testTargetAttachment() { + $url = new SimpleUrl('http://www.site.com/home.html'); + $this->assertIdentical($url->getTarget(), false); + $url->setTarget('A frame'); + $this->assertIdentical($url->getTarget(), 'A frame'); + } +} + +/** + * @note Based off of http://www.mozilla.org/quality/networking/testing/filetests.html + */ +class TestOfFileUrl extends UnitTestCase { + + function testMinimalUrl() { + $url = new SimpleUrl('file:///'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/'); + } + + function testUnixUrl() { + $url = new SimpleUrl('file:///fileInRoot'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/fileInRoot'); + } + + function testDOSVolumeUrl() { + $url = new SimpleUrl('file:///C:/config.sys'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/C:/config.sys'); + } + + function testDOSVolumePromotion() { + $url = new SimpleUrl('file://C:/config.sys'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/C:/config.sys'); + } + + function testDOSBackslashes() { + $url = new SimpleUrl('file:///C:\config.sys'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/C:/config.sys'); + } + + function testDOSDirnameAfterFile() { + $url = new SimpleUrl('file://C:\config.sys'); + $this->assertEqual($url->getScheme(), 'file'); + $this->assertIdentical($url->getHost(), false); + $this->assertEqual($url->getPath(), '/C:/config.sys'); + } + +} + +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/user_agent_test.php b/application/libraries/simpletest/test/user_agent_test.php new file mode 100644 index 00000000000..030abeb257d --- /dev/null +++ b/application/libraries/simpletest/test/user_agent_test.php @@ -0,0 +1,348 @@ +headers = new MockSimpleHttpHeaders(); + $this->response = new MockSimpleHttpResponse(); + $this->response->setReturnValue('isError', false); + $this->response->returns('getHeaders', new MockSimpleHttpHeaders()); + $this->request = new MockSimpleHttpRequest(); + $this->request->returns('fetch', $this->response); + } + + function testGetRequestWithoutIncidentGivesNoErrors() { + $url = new SimpleUrl('http://test:secret@this.com/page.html'); + $url->addRequestParameters(array('a' => 'A', 'b' => 'B')); + + $agent = new MockRequestUserAgent(); + $agent->returns('createHttpRequest', $this->request); + $agent->__construct(); + + $response = $agent->fetchResponse( + new SimpleUrl('http://test:secret@this.com/page.html'), + new SimpleGetEncoding(array('a' => 'A', 'b' => 'B'))); + $this->assertFalse($response->isError()); + } +} + +class TestOfAdditionalHeaders extends UnitTestCase { + + function testAdditionalHeaderAddedToRequest() { + $response = new MockSimpleHttpResponse(); + $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders()); + + $request = new MockSimpleHttpRequest(); + $request->setReturnReference('fetch', $response); + $request->expectOnce( + 'addHeaderLine', + array('User-Agent: SimpleTest')); + + $agent = new MockRequestUserAgent(); + $agent->setReturnReference('createHttpRequest', $request); + $agent->__construct(); + $agent->addHeader('User-Agent: SimpleTest'); + $response = $agent->fetchResponse(new SimpleUrl('http://this.host/'), new SimpleGetEncoding()); + } +} + +class TestOfBrowserCookies extends UnitTestCase { + + private function createStandardResponse() { + $response = new MockSimpleHttpResponse(); + $response->setReturnValue("isError", false); + $response->setReturnValue("getContent", "stuff"); + $response->setReturnReference("getHeaders", new MockSimpleHttpHeaders()); + return $response; + } + + private function createCookieSite($header_lines) { + $headers = new SimpleHttpHeaders($header_lines); + $response = new MockSimpleHttpResponse(); + $response->setReturnValue("isError", false); + $response->setReturnReference("getHeaders", $headers); + $response->setReturnValue("getContent", "stuff"); + $request = new MockSimpleHttpRequest(); + $request->setReturnReference("fetch", $response); + return $request; + } + + private function createMockedRequestUserAgent(&$request) { + $agent = new MockRequestUserAgent(); + $agent->setReturnReference('createHttpRequest', $request); + $agent->__construct(); + return $agent; + } + + function testCookieJarIsSentToRequest() { + $jar = new SimpleCookieJar(); + $jar->setCookie('a', 'A'); + + $request = new MockSimpleHttpRequest(); + $request->returns('fetch', $this->createStandardResponse()); + $request->expectOnce('readCookiesFromJar', array($jar, '*')); + + $agent = $this->createMockedRequestUserAgent($request); + $agent->setCookie('a', 'A'); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + } + + function testNoCookieJarIsSentToRequestWhenCookiesAreDisabled() { + $request = new MockSimpleHttpRequest(); + $request->returns('fetch', $this->createStandardResponse()); + $request->expectNever('readCookiesFromJar'); + + $agent = $this->createMockedRequestUserAgent($request); + $agent->setCookie('a', 'A'); + $agent->ignoreCookies(); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + } + + function testReadingNewCookie() { + $request = $this->createCookieSite('Set-cookie: a=AAAA'); + $agent = $this->createMockedRequestUserAgent($request); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA"); + } + + function testIgnoringNewCookieWhenCookiesDisabled() { + $request = $this->createCookieSite('Set-cookie: a=AAAA'); + $agent = $this->createMockedRequestUserAgent($request); + $agent->ignoreCookies(); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $this->assertIdentical($agent->getCookieValue("this.com", "this/path/", "a"), false); + } + + function testOverwriteCookieThatAlreadyExists() { + $request = $this->createCookieSite('Set-cookie: a=AAAA'); + $agent = $this->createMockedRequestUserAgent($request); + $agent->setCookie('a', 'A'); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA"); + } + + function testClearCookieBySettingExpiry() { + $request = $this->createCookieSite('Set-cookie: a=b'); + $agent = $this->createMockedRequestUserAgent($request); + + $agent->setCookie("a", "A", "this/path/", "Wed, 25-Dec-02 04:24:21 GMT"); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $this->assertIdentical( + $agent->getCookieValue("this.com", "this/path/", "a"), + "b"); + $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); + $this->assertIdentical( + $agent->getCookieValue("this.com", "this/path/", "a"), + false); + } + + function testAgeingAndClearing() { + $request = $this->createCookieSite('Set-cookie: a=A; expires=Wed, 25-Dec-02 04:24:21 GMT; path=/this/path'); + $agent = $this->createMockedRequestUserAgent($request); + + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); + $this->assertIdentical( + $agent->getCookieValue("this.com", "this/path/", "a"), + "A"); + $agent->ageCookies(2); + $agent->restart("Wed, 25-Dec-02 04:24:20 GMT"); + $this->assertIdentical( + $agent->getCookieValue("this.com", "this/path/", "a"), + false); + } + + function testReadingIncomingAndSettingNewCookies() { + $request = $this->createCookieSite('Set-cookie: a=AAA'); + $agent = $this->createMockedRequestUserAgent($request); + + $this->assertNull($agent->getBaseCookieValue("a", false)); + $agent->fetchResponse( + new SimpleUrl('http://this.com/this/path/page.html'), + new SimpleGetEncoding()); + $agent->setCookie("b", "BBB", "this.com", "this/path/"); + $this->assertEqual( + $agent->getBaseCookieValue("a", new SimpleUrl('http://this.com/this/path/page.html')), + "AAA"); + $this->assertEqual( + $agent->getBaseCookieValue("b", new SimpleUrl('http://this.com/this/path/page.html')), + "BBB"); + } +} + +class TestOfHttpRedirects extends UnitTestCase { + + function createRedirect($content, $redirect) { + $headers = new MockSimpleHttpHeaders(); + $headers->setReturnValue('isRedirect', (boolean)$redirect); + $headers->setReturnValue('getLocation', $redirect); + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('getContent', $content); + $response->setReturnReference('getHeaders', $headers); + $request = new MockSimpleHttpRequest(); + $request->setReturnReference('fetch', $response); + return $request; + } + + function testDisabledRedirects() { + $agent = new MockRequestUserAgent(); + $agent->returns( + 'createHttpRequest', + $this->createRedirect('stuff', 'there.html')); + $agent->expectOnce('createHttpRequest'); + $agent->__construct(); + $agent->setMaximumRedirects(0); + $response = $agent->fetchResponse(new SimpleUrl('here.html'), new SimpleGetEncoding()); + $this->assertEqual($response->getContent(), 'stuff'); + } + + function testSingleRedirect() { + $agent = new MockRequestUserAgent(); + $agent->returnsAt( + 0, + 'createHttpRequest', + $this->createRedirect('first', 'two.html')); + $agent->returnsAt( + 1, + 'createHttpRequest', + $this->createRedirect('second', 'three.html')); + $agent->expectCallCount('createHttpRequest', 2); + $agent->__construct(); + + $agent->setMaximumRedirects(1); + $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); + $this->assertEqual($response->getContent(), 'second'); + } + + function testDoubleRedirect() { + $agent = new MockRequestUserAgent(); + $agent->returnsAt( + 0, + 'createHttpRequest', + $this->createRedirect('first', 'two.html')); + $agent->returnsAt( + 1, + 'createHttpRequest', + $this->createRedirect('second', 'three.html')); + $agent->returnsAt( + 2, + 'createHttpRequest', + $this->createRedirect('third', 'four.html')); + $agent->expectCallCount('createHttpRequest', 3); + $agent->__construct(); + + $agent->setMaximumRedirects(2); + $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); + $this->assertEqual($response->getContent(), 'third'); + } + + function testSuccessAfterRedirect() { + $agent = new MockRequestUserAgent(); + $agent->returnsAt( + 0, + 'createHttpRequest', + $this->createRedirect('first', 'two.html')); + $agent->returnsAt( + 1, + 'createHttpRequest', + $this->createRedirect('second', false)); + $agent->returnsAt( + 2, + 'createHttpRequest', + $this->createRedirect('third', 'four.html')); + $agent->expectCallCount('createHttpRequest', 2); + $agent->__construct(); + + $agent->setMaximumRedirects(2); + $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding()); + $this->assertEqual($response->getContent(), 'second'); + } + + function testRedirectChangesPostToGet() { + $agent = new MockRequestUserAgent(); + $agent->returnsAt( + 0, + 'createHttpRequest', + $this->createRedirect('first', 'two.html')); + $agent->expectAt(0, 'createHttpRequest', array('*', new IsAExpectation('SimplePostEncoding'))); + $agent->returnsAt( + 1, + 'createHttpRequest', + $this->createRedirect('second', 'three.html')); + $agent->expectAt(1, 'createHttpRequest', array('*', new IsAExpectation('SimpleGetEncoding'))); + $agent->expectCallCount('createHttpRequest', 2); + $agent->__construct(); + $agent->setMaximumRedirects(1); + $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimplePostEncoding()); + } +} + +class TestOfBadHosts extends UnitTestCase { + + private function createSimulatedBadHost() { + $response = new MockSimpleHttpResponse(); + $response->setReturnValue('isError', true); + $response->setReturnValue('getError', 'Bad socket'); + $response->setReturnValue('getContent', false); + $request = new MockSimpleHttpRequest(); + $request->setReturnReference('fetch', $response); + return $request; + } + + function testUntestedHost() { + $request = $this->createSimulatedBadHost(); + $agent = new MockRequestUserAgent(); + $agent->setReturnReference('createHttpRequest', $request); + $agent->__construct(); + $response = $agent->fetchResponse( + new SimpleUrl('http://this.host/this/path/page.html'), + new SimpleGetEncoding()); + $this->assertTrue($response->isError()); + } +} + +class TestOfAuthorisation extends UnitTestCase { + + function testAuthenticateHeaderAdded() { + $response = new MockSimpleHttpResponse(); + $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders()); + + $request = new MockSimpleHttpRequest(); + $request->returns('fetch', $response); + $request->expectOnce( + 'addHeaderLine', + array('Authorization: Basic ' . base64_encode('test:secret'))); + + $agent = new MockRequestUserAgent(); + $agent->returns('createHttpRequest', $request); + $agent->__construct(); + $response = $agent->fetchResponse( + new SimpleUrl('http://test:secret@this.host'), + new SimpleGetEncoding()); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/visual_test.php b/application/libraries/simpletest/test/visual_test.php new file mode 100644 index 00000000000..6b9d085d67f --- /dev/null +++ b/application/libraries/simpletest/test/visual_test.php @@ -0,0 +1,495 @@ +a = $a; + } +} + +class PassingUnitTestCaseOutput extends UnitTestCase { + + function testOfResults() { + $this->pass('Pass'); + } + + function testTrue() { + $this->assertTrue(true); + } + + function testFalse() { + $this->assertFalse(false); + } + + function testExpectation() { + $expectation = &new EqualExpectation(25, 'My expectation message: %s'); + $this->assert($expectation, 25, 'My assert message : %s'); + } + + function testNull() { + $this->assertNull(null, "%s -> Pass"); + $this->assertNotNull(false, "%s -> Pass"); + } + + function testType() { + $this->assertIsA("hello", "string", "%s -> Pass"); + $this->assertIsA($this, "PassingUnitTestCaseOutput", "%s -> Pass"); + $this->assertIsA($this, "UnitTestCase", "%s -> Pass"); + } + + function testTypeEquality() { + $this->assertEqual("0", 0, "%s -> Pass"); + } + + function testNullEquality() { + $this->assertNotEqual(null, 1, "%s -> Pass"); + $this->assertNotEqual(1, null, "%s -> Pass"); + } + + function testIntegerEquality() { + $this->assertNotEqual(1, 2, "%s -> Pass"); + } + + function testStringEquality() { + $this->assertEqual("a", "a", "%s -> Pass"); + $this->assertNotEqual("aa", "ab", "%s -> Pass"); + } + + function testHashEquality() { + $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> Pass"); + } + + function testWithin() { + $this->assertWithinMargin(5, 5.4, 0.5, "%s -> Pass"); + } + + function testOutside() { + $this->assertOutsideMargin(5, 5.6, 0.5, "%s -> Pass"); + } + + function testStringIdentity() { + $a = "fred"; + $b = $a; + $this->assertIdentical($a, $b, "%s -> Pass"); + } + + function testTypeIdentity() { + $a = "0"; + $b = 0; + $this->assertNotIdentical($a, $b, "%s -> Pass"); + } + + function testNullIdentity() { + $this->assertNotIdentical(null, 1, "%s -> Pass"); + $this->assertNotIdentical(1, null, "%s -> Pass"); + } + + function testHashIdentity() { + } + + function testObjectEquality() { + $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Pass"); + $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Pass"); + } + + function testObjectIndentity() { + $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Pass"); + $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Pass"); + } + + function testReference() { + $a = "fred"; + $b = &$a; + $this->assertReference($a, $b, "%s -> Pass"); + } + + function testCloneOnDifferentObjects() { + $a = "fred"; + $b = $a; + $c = "Hello"; + $this->assertClone($a, $b, "%s -> Pass"); + } + + function testPatterns() { + $this->assertPattern('/hello/i', "Hello there", "%s -> Pass"); + $this->assertNoPattern('/hello/', "Hello there", "%s -> Pass"); + } + + function testLongStrings() { + $text = ""; + for ($i = 0; $i < 10; $i++) { + $text .= "0123456789"; + } + $this->assertEqual($text, $text); + } +} + +class FailingUnitTestCaseOutput extends UnitTestCase { + + function testOfResults() { + $this->fail('Fail'); // Fail. + } + + function testTrue() { + $this->assertTrue(false); // Fail. + } + + function testFalse() { + $this->assertFalse(true); // Fail. + } + + function testExpectation() { + $expectation = &new EqualExpectation(25, 'My expectation message: %s'); + $this->assert($expectation, 24, 'My assert message : %s'); // Fail. + } + + function testNull() { + $this->assertNull(false, "%s -> Fail"); // Fail. + $this->assertNotNull(null, "%s -> Fail"); // Fail. + } + + function testType() { + $this->assertIsA(14, "string", "%s -> Fail"); // Fail. + $this->assertIsA(14, "TestOfUnitTestCaseOutput", "%s -> Fail"); // Fail. + $this->assertIsA($this, "TestReporter", "%s -> Fail"); // Fail. + } + + function testTypeEquality() { + $this->assertNotEqual("0", 0, "%s -> Fail"); // Fail. + } + + function testNullEquality() { + $this->assertEqual(null, 1, "%s -> Fail"); // Fail. + $this->assertEqual(1, null, "%s -> Fail"); // Fail. + } + + function testIntegerEquality() { + $this->assertEqual(1, 2, "%s -> Fail"); // Fail. + } + + function testStringEquality() { + $this->assertNotEqual("a", "a", "%s -> Fail"); // Fail. + $this->assertEqual("aa", "ab", "%s -> Fail"); // Fail. + } + + function testHashEquality() { + $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "Z"), "%s -> Fail"); + } + + function testWithin() { + $this->assertWithinMargin(5, 5.6, 0.5, "%s -> Fail"); // Fail. + } + + function testOutside() { + $this->assertOutsideMargin(5, 5.4, 0.5, "%s -> Fail"); // Fail. + } + + function testStringIdentity() { + $a = "fred"; + $b = $a; + $this->assertNotIdentical($a, $b, "%s -> Fail"); // Fail. + } + + function testTypeIdentity() { + $a = "0"; + $b = 0; + $this->assertIdentical($a, $b, "%s -> Fail"); // Fail. + } + + function testNullIdentity() { + $this->assertIdentical(null, 1, "%s -> Fail"); // Fail. + $this->assertIdentical(1, null, "%s -> Fail"); // Fail. + } + + function testHashIdentity() { + $this->assertIdentical(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> fail"); // Fail. + } + + function testObjectEquality() { + $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Fail"); // Fail. + $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Fail"); // Fail. + } + + function testObjectIndentity() { + $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Fail"); // Fail. + $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Fail"); // Fail. + } + + function testReference() { + $a = "fred"; + $b = &$a; + $this->assertClone($a, $b, "%s -> Fail"); // Fail. + } + + function testCloneOnDifferentObjects() { + $a = "fred"; + $b = $a; + $c = "Hello"; + $this->assertClone($a, $c, "%s -> Fail"); // Fail. + } + + function testPatterns() { + $this->assertPattern('/hello/', "Hello there", "%s -> Fail"); // Fail. + $this->assertNoPattern('/hello/i', "Hello there", "%s -> Fail"); // Fail. + } + + function testLongStrings() { + $text = ""; + for ($i = 0; $i < 10; $i++) { + $text .= "0123456789"; + } + $this->assertEqual($text . $text, $text . "a" . $text); // Fail. + } +} + +class Dummy { + function Dummy() { + } + + function a() { + } +} +Mock::generate('Dummy'); + +class TestOfMockObjectsOutput extends UnitTestCase { + + function testCallCounts() { + $dummy = &new MockDummy(); + $dummy->expectCallCount('a', 1, 'My message: %s'); + $dummy->a(); + $dummy->a(); + } + + function testMinimumCallCounts() { + $dummy = &new MockDummy(); + $dummy->expectMinimumCallCount('a', 2, 'My message: %s'); + $dummy->a(); + $dummy->a(); + } + + function testEmptyMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array()); + $dummy->a(); + $dummy->a(null); // Fail. + } + + function testEmptyMatchingWithCustomMessage() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(), 'My expectation message: %s'); + $dummy->a(); + $dummy->a(null); // Fail. + } + + function testNullMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(null)); + $dummy->a(null); + $dummy->a(); // Fail. + } + + function testBooleanMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(true, false)); + $dummy->a(true, false); + $dummy->a(true, true); // Fail. + } + + function testIntegerMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(32, 33)); + $dummy->a(32, 33); + $dummy->a(32, 34); // Fail. + } + + function testFloatMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(3.2, 3.3)); + $dummy->a(3.2, 3.3); + $dummy->a(3.2, 3.4); // Fail. + } + + function testStringMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array('32', '33')); + $dummy->a('32', '33'); + $dummy->a('32', '34'); // Fail. + } + + function testEmptyMatchingWithCustomExpectationMessage() { + $dummy = &new MockDummy(); + $dummy->expect( + 'a', + array(new EqualExpectation('A', 'My part expectation message: %s')), + 'My expectation message: %s'); + $dummy->a('A'); + $dummy->a('B'); // Fail. + } + + function testArrayMatching() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(array(32), array(33))); + $dummy->a(array(32), array(33)); + $dummy->a(array(32), array('33')); // Fail. + } + + function testObjectMatching() { + $a = new Dummy(); + $a->a = 'a'; + $b = new Dummy(); + $b->b = 'b'; + $dummy = &new MockDummy(); + $dummy->expect('a', array($a, $b)); + $dummy->a($a, $b); + $dummy->a($a, $a); // Fail. + } + + function testBigList() { + $dummy = &new MockDummy(); + $dummy->expect('a', array(false, 0, 1, 1.0)); + $dummy->a(false, 0, 1, 1.0); + $dummy->a(true, false, 2, 2.0); // Fail. + } +} + +class TestOfPastBugs extends UnitTestCase { + + function testMixedTypes() { + $this->assertEqual(array(), null, "%s -> Pass"); + $this->assertIdentical(array(), null, "%s -> Fail"); // Fail. + } + + function testMockWildcards() { + $dummy = &new MockDummy(); + $dummy->expect('a', array('*', array(33))); + $dummy->a(array(32), array(33)); + $dummy->a(array(32), array('33')); // Fail. + } +} + +class TestOfVisualShell extends ShellTestCase { + + function testDump() { + $this->execute('ls'); + $this->dumpOutput(); + $this->execute('dir'); + $this->dumpOutput(); + } + + function testDumpOfList() { + $this->execute('ls'); + $this->dump($this->getOutputAsList()); + } +} + +class PassesAsWellReporter extends HtmlReporter { + + protected function getCss() { + return parent::getCss() . ' .pass { color: darkgreen; }'; + } + + function paintPass($message) { + parent::paintPass($message); + print "Pass: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . htmlentities($message) . "
    \n"; + } + + function paintSignal($type, &$payload) { + print "$type: "; + $breadcrumb = $this->getTestList(); + array_shift($breadcrumb); + print implode(" -> ", $breadcrumb); + print " -> " . htmlentities(serialize($payload)) . "
    \n"; + } +} + +class TestOfSkippingNoMatterWhat extends UnitTestCase { + function skip() { + $this->skipIf(true, 'Always skipped -> %s'); + } + + function testFail() { + $this->fail('This really shouldn\'t have happened'); + } +} + +class TestOfSkippingOrElse extends UnitTestCase { + function skip() { + $this->skipUnless(false, 'Always skipped -> %s'); + } + + function testFail() { + $this->fail('This really shouldn\'t have happened'); + } +} + +class TestOfSkippingTwiceOver extends UnitTestCase { + function skip() { + $this->skipIf(true, 'First reason -> %s'); + $this->skipIf(true, 'Second reason -> %s'); + } + + function testFail() { + $this->fail('This really shouldn\'t have happened'); + } +} + +class TestThatShouldNotBeSkipped extends UnitTestCase { + function skip() { + $this->skipIf(false); + $this->skipUnless(true); + } + + function testFail() { + $this->fail('We should see this message'); + } + + function testPass() { + $this->pass('We should see this message'); + } +} + +$test = &new TestSuite('Visual test with 46 passes, 47 fails and 0 exceptions'); +$test->add(new PassingUnitTestCaseOutput()); +$test->add(new FailingUnitTestCaseOutput()); +$test->add(new TestOfMockObjectsOutput()); +$test->add(new TestOfPastBugs()); +$test->add(new TestOfVisualShell()); +$test->add(new TestOfSkippingNoMatterWhat()); +$test->add(new TestOfSkippingOrElse()); +$test->add(new TestOfSkippingTwiceOver()); +$test->add(new TestThatShouldNotBeSkipped()); + +if (isset($_GET['xml']) || in_array('xml', (isset($argv) ? $argv : array()))) { + $reporter = new XmlReporter(); +} elseif (TextReporter::inCli()) { + $reporter = new TextReporter(); +} else { + $reporter = new PassesAsWellReporter(); +} +if (isset($_GET['dry']) || in_array('dry', (isset($argv) ? $argv : array()))) { + $reporter->makeDry(); +} +exit ($test->run($reporter) ? 0 : 1); +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/web_tester_test.php b/application/libraries/simpletest/test/web_tester_test.php new file mode 100644 index 00000000000..8c3bf1adf63 --- /dev/null +++ b/application/libraries/simpletest/test/web_tester_test.php @@ -0,0 +1,155 @@ +assertTrue($expectation->test('a')); + $this->assertTrue($expectation->test(array('a'))); + $this->assertFalse($expectation->test('A')); + } + + function testMatchesInteger() { + $expectation = new FieldExpectation('1'); + $this->assertTrue($expectation->test('1')); + $this->assertTrue($expectation->test(1)); + $this->assertTrue($expectation->test(array('1'))); + $this->assertTrue($expectation->test(array(1))); + } + + function testNonStringFailsExpectation() { + $expectation = new FieldExpectation('a'); + $this->assertFalse($expectation->test(null)); + } + + function testUnsetFieldCanBeTestedFor() { + $expectation = new FieldExpectation(false); + $this->assertTrue($expectation->test(false)); + } + + function testMultipleValuesCanBeInAnyOrder() { + $expectation = new FieldExpectation(array('a', 'b')); + $this->assertTrue($expectation->test(array('a', 'b'))); + $this->assertTrue($expectation->test(array('b', 'a'))); + $this->assertFalse($expectation->test(array('a', 'a'))); + $this->assertFalse($expectation->test('a')); + } + + function testSingleItemCanBeArrayOrString() { + $expectation = new FieldExpectation(array('a')); + $this->assertTrue($expectation->test(array('a'))); + $this->assertTrue($expectation->test('a')); + } +} + +class TestOfHeaderExpectations extends UnitTestCase { + + function testExpectingOnlyTheHeaderName() { + $expectation = new HttpHeaderExpectation('a'); + $this->assertIdentical($expectation->test(false), false); + $this->assertIdentical($expectation->test('a: A'), true); + $this->assertIdentical($expectation->test('A: A'), true); + $this->assertIdentical($expectation->test('a: B'), true); + $this->assertIdentical($expectation->test(' a : A '), true); + } + + function testHeaderValueAsWell() { + $expectation = new HttpHeaderExpectation('a', 'A'); + $this->assertIdentical($expectation->test(false), false); + $this->assertIdentical($expectation->test('a: A'), true); + $this->assertIdentical($expectation->test('A: A'), true); + $this->assertIdentical($expectation->test('A: a'), false); + $this->assertIdentical($expectation->test('a: B'), false); + $this->assertIdentical($expectation->test(' a : A '), true); + $this->assertIdentical($expectation->test(' a : AB '), false); + } + + function testHeaderValueWithColons() { + $expectation = new HttpHeaderExpectation('a', 'A:B:C'); + $this->assertIdentical($expectation->test('a: A'), false); + $this->assertIdentical($expectation->test('a: A:B'), false); + $this->assertIdentical($expectation->test('a: A:B:C'), true); + $this->assertIdentical($expectation->test('a: A:B:C:D'), false); + } + + function testMultilineSearch() { + $expectation = new HttpHeaderExpectation('a', 'A'); + $this->assertIdentical($expectation->test("aa: A\r\nb: B\r\nc: C"), false); + $this->assertIdentical($expectation->test("aa: A\r\na: A\r\nb: B"), true); + } + + function testMultilineSearchWithPadding() { + $expectation = new HttpHeaderExpectation('a', ' A '); + $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), false); + $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), true); + } + + function testPatternMatching() { + $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/')); + $this->assertIdentical($expectation->test('a: A'), true); + $this->assertIdentical($expectation->test('A: A'), true); + $this->assertIdentical($expectation->test('A: a'), false); + $this->assertIdentical($expectation->test('a: B'), false); + $this->assertIdentical($expectation->test(' a : A '), true); + $this->assertIdentical($expectation->test(' a : AB '), true); + } + + function testCaseInsensitivePatternMatching() { + $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/i')); + $this->assertIdentical($expectation->test('a: a'), true); + $this->assertIdentical($expectation->test('a: B'), false); + $this->assertIdentical($expectation->test(' a : A '), true); + $this->assertIdentical($expectation->test(' a : BAB '), true); + $this->assertIdentical($expectation->test(' a : bab '), true); + } + + function testUnwantedHeader() { + $expectation = new NoHttpHeaderExpectation('a'); + $this->assertIdentical($expectation->test(''), true); + $this->assertIdentical($expectation->test('stuff'), true); + $this->assertIdentical($expectation->test('b: B'), true); + $this->assertIdentical($expectation->test('a: A'), false); + $this->assertIdentical($expectation->test('A: A'), false); + } + + function testMultilineUnwantedSearch() { + $expectation = new NoHttpHeaderExpectation('a'); + $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), true); + $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), false); + } + + function testLocationHeaderSplitsCorrectly() { + $expectation = new HttpHeaderExpectation('Location', 'http://here/'); + $this->assertIdentical($expectation->test('Location: http://here/'), true); + } +} + +class TestOfTextExpectations extends UnitTestCase { + + function testMatchingSubString() { + $expectation = new TextExpectation('wanted'); + $this->assertIdentical($expectation->test(''), false); + $this->assertIdentical($expectation->test('Wanted'), false); + $this->assertIdentical($expectation->test('wanted'), true); + $this->assertIdentical($expectation->test('the wanted text is here'), true); + } + + function testNotMatchingSubString() { + $expectation = new NoTextExpectation('wanted'); + $this->assertIdentical($expectation->test(''), true); + $this->assertIdentical($expectation->test('Wanted'), true); + $this->assertIdentical($expectation->test('wanted'), false); + $this->assertIdentical($expectation->test('the wanted text is here'), false); + } +} + +class TestOfGenericAssertionsInWebTester extends WebTestCase { + function testEquality() { + $this->assertEqual('a', 'a'); + $this->assertNotEqual('a', 'A'); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test/xml_test.php b/application/libraries/simpletest/test/xml_test.php new file mode 100644 index 00000000000..f99e0dcd98b --- /dev/null +++ b/application/libraries/simpletest/test/xml_test.php @@ -0,0 +1,187 @@ + 2)); + $this->assertEqual($nesting->getSize(), 2); + } +} + +class TestOfXmlStructureParsing extends UnitTestCase { + function testValidXml() { + $listener = new MockSimpleScorer(); + $listener->expectNever('paintGroupStart'); + $listener->expectNever('paintGroupEnd'); + $listener->expectNever('paintCaseStart'); + $listener->expectNever('paintCaseEnd'); + $parser = new SimpleTestXmlParser($listener); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("\n")); + } + + function testEmptyGroup() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintGroupStart', array('a_group', 7)); + $listener->expectOnce('paintGroupEnd', array('a_group')); + $parser = new SimpleTestXmlParser($listener); + $parser->parse("\n"); + $parser->parse("\n"); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("a_group\n")); + $this->assertTrue($parser->parse("\n")); + $parser->parse("\n"); + } + + function testEmptyCase() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintCaseStart', array('a_case')); + $listener->expectOnce('paintCaseEnd', array('a_case')); + $parser = new SimpleTestXmlParser($listener); + $parser->parse("\n"); + $parser->parse("\n"); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("a_case\n")); + $this->assertTrue($parser->parse("\n")); + $parser->parse("\n"); + } + + function testEmptyMethod() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintCaseStart', array('a_case')); + $listener->expectOnce('paintCaseEnd', array('a_case')); + $listener->expectOnce('paintMethodStart', array('a_method')); + $listener->expectOnce('paintMethodEnd', array('a_method')); + $parser = new SimpleTestXmlParser($listener); + $parser->parse("\n"); + $parser->parse("\n"); + $parser->parse("\n"); + $parser->parse("a_case\n"); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("a_method\n")); + $this->assertTrue($parser->parse("\n")); + $parser->parse("\n"); + $parser->parse("\n"); + } + + function testNestedGroup() { + $listener = new MockSimpleScorer(); + $listener->expectAt(0, 'paintGroupStart', array('a_group', 7)); + $listener->expectAt(1, 'paintGroupStart', array('b_group', 3)); + $listener->expectCallCount('paintGroupStart', 2); + $listener->expectAt(0, 'paintGroupEnd', array('b_group')); + $listener->expectAt(1, 'paintGroupEnd', array('a_group')); + $listener->expectCallCount('paintGroupEnd', 2); + + $parser = new SimpleTestXmlParser($listener); + $parser->parse("\n"); + $parser->parse("\n"); + + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("a_group\n")); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("b_group\n")); + $this->assertTrue($parser->parse("\n")); + $this->assertTrue($parser->parse("\n")); + $parser->parse("\n"); + } +} + +class AnyOldSignal { + public $stuff = true; +} + +class TestOfXmlResultsParsing extends UnitTestCase { + + function sendValidStart(&$parser) { + $parser->parse("\n"); + $parser->parse("\n"); + $parser->parse("\n"); + $parser->parse("a_case\n"); + $parser->parse("\n"); + $parser->parse("a_method\n"); + } + + function sendValidEnd(&$parser) { + $parser->parse("\n"); + $parser->parse("\n"); + $parser->parse("\n"); + } + + function testPass() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintPass', array('a_message')); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("a_message\n")); + $this->sendValidEnd($parser); + } + + function testFail() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintFail', array('a_message')); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("a_message\n")); + $this->sendValidEnd($parser); + } + + function testException() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintError', array('a_message')); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("a_message\n")); + $this->sendValidEnd($parser); + } + + function testSkip() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintSkip', array('a_message')); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("a_message\n")); + $this->sendValidEnd($parser); + } + + function testSignal() { + $signal = new AnyOldSignal(); + $signal->stuff = "Hello"; + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintSignal', array('a_signal', $signal)); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse( + "\n")); + $this->sendValidEnd($parser); + } + + function testMessage() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintMessage', array('a_message')); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("a_message\n")); + $this->sendValidEnd($parser); + } + + function testFormattedMessage() { + $listener = new MockSimpleScorer(); + $listener->expectOnce('paintFormattedMessage', array("\na\tmessage\n")); + $parser = new SimpleTestXmlParser($listener); + $this->sendValidStart($parser); + $this->assertTrue($parser->parse("\n")); + $this->sendValidEnd($parser); + } +} +?> \ No newline at end of file diff --git a/application/libraries/simpletest/test_case.php b/application/libraries/simpletest/test_case.php new file mode 100644 index 00000000000..ba023c3b2ea --- /dev/null +++ b/application/libraries/simpletest/test_case.php @@ -0,0 +1,658 @@ +label = $label; + } + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->label ? $this->label : get_class($this); + } + + /** + * This is a placeholder for skipping tests. In this + * method you place skipIf() and skipUnless() calls to + * set the skipping state. + * @access public + */ + function skip() { + } + + /** + * Will issue a message to the reporter and tell the test + * case to skip if the incoming flag is true. + * @param string $should_skip Condition causing the tests to be skipped. + * @param string $message Text of skip condition. + * @access public + */ + function skipIf($should_skip, $message = '%s') { + if ($should_skip && ! $this->should_skip) { + $this->should_skip = true; + $message = sprintf($message, 'Skipping [' . get_class($this) . ']'); + $this->reporter->paintSkip($message . $this->getAssertionLine()); + } + } + + /** + * Accessor for the private variable $_shoud_skip + * @access public + */ + function shouldSkip() { + return $this->should_skip; + } + + /** + * Will issue a message to the reporter and tell the test + * case to skip if the incoming flag is false. + * @param string $shouldnt_skip Condition causing the tests to be run. + * @param string $message Text of skip condition. + * @access public + */ + function skipUnless($shouldnt_skip, $message = false) { + $this->skipIf(! $shouldnt_skip, $message); + } + + /** + * Used to invoke the single tests. + * @return SimpleInvoker Individual test runner. + * @access public + */ + function createInvoker() { + return new SimpleErrorTrappingInvoker( + new SimpleExceptionTrappingInvoker(new SimpleInvoker($this))); + } + + /** + * Uses reflection to run every method within itself + * starting with the string "test" unless a method + * is specified. + * @param SimpleReporter $reporter Current test reporter. + * @return boolean True if all tests passed. + * @access public + */ + function run($reporter) { + $context = SimpleTest::getContext(); + $context->setTest($this); + $context->setReporter($reporter); + $this->reporter = $reporter; + $started = false; + foreach ($this->getTests() as $method) { + if ($reporter->shouldInvoke($this->getLabel(), $method)) { + $this->skip(); + if ($this->should_skip) { + break; + } + if (! $started) { + $reporter->paintCaseStart($this->getLabel()); + $started = true; + } + $invoker = $this->reporter->createInvoker($this->createInvoker()); + $invoker->before($method); + $invoker->invoke($method); + $invoker->after($method); + } + } + if ($started) { + $reporter->paintCaseEnd($this->getLabel()); + } + unset($this->reporter); + $context->setTest(null); + return $reporter->getStatus(); + } + + /** + * Gets a list of test names. Normally that will + * be all internal methods that start with the + * name "test". This method should be overridden + * if you want a different rule. + * @return array List of test names. + * @access public + */ + function getTests() { + $methods = array(); + foreach (get_class_methods(get_class($this)) as $method) { + if ($this->isTest($method)) { + $methods[] = $method; + } + } + return $methods; + } + + /** + * Tests to see if the method is a test that should + * be run. Currently any method that starts with 'test' + * is a candidate unless it is the constructor. + * @param string $method Method name to try. + * @return boolean True if test method. + * @access protected + */ + protected function isTest($method) { + if (strtolower(substr($method, 0, 4)) == 'test') { + return ! SimpleTestCompatibility::isA($this, strtolower($method)); + } + return false; + } + + /** + * Announces the start of the test. + * @param string $method Test method just started. + * @access public + */ + function before($method) { + $this->reporter->paintMethodStart($method); + $this->observers = array(); + } + + /** + * Sets up unit test wide variables at the start + * of each test method. To be overridden in + * actual user test cases. + * @access public + */ + function setUp() { + } + + /** + * Clears the data set in the setUp() method call. + * To be overridden by the user in actual user test cases. + * @access public + */ + function tearDown() { + } + + /** + * Announces the end of the test. Includes private clean up. + * @param string $method Test method just finished. + * @access public + */ + function after($method) { + for ($i = 0; $i < count($this->observers); $i++) { + $this->observers[$i]->atTestEnd($method, $this); + } + $this->reporter->paintMethodEnd($method); + } + + /** + * Sets up an observer for the test end. + * @param object $observer Must have atTestEnd() + * method. + * @access public + */ + function tell($observer) { + $this->observers[] = &$observer; + } + + /** + * @deprecated + */ + function pass($message = "Pass") { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintPass( + $message . $this->getAssertionLine()); + return true; + } + + /** + * Sends a fail event with a message. + * @param string $message Message to send. + * @access public + */ + function fail($message = "Fail") { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintFail( + $message . $this->getAssertionLine()); + return false; + } + + /** + * Formats a PHP error and dispatches it to the + * reporter. + * @param integer $severity PHP error code. + * @param string $message Text of error. + * @param string $file File error occoured in. + * @param integer $line Line number of error. + * @access public + */ + function error($severity, $message, $file, $line) { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintError( + "Unexpected PHP error [$message] severity [$severity] in [$file line $line]"); + } + + /** + * Formats an exception and dispatches it to the + * reporter. + * @param Exception $exception Object thrown. + * @access public + */ + function exception($exception) { + $this->reporter->paintException($exception); + } + + /** + * For user defined expansion of the available messages. + * @param string $type Tag for sorting the signals. + * @param mixed $payload Extra user specific information. + */ + function signal($type, $payload) { + if (! isset($this->reporter)) { + trigger_error('Can only make assertions within test methods'); + } + $this->reporter->paintSignal($type, $payload); + } + + /** + * Runs an expectation directly, for extending the + * tests with new expectation classes. + * @param SimpleExpectation $expectation Expectation subclass. + * @param mixed $compare Value to compare. + * @param string $message Message to display. + * @return boolean True on pass + * @access public + */ + function assert($expectation, $compare, $message = '%s') { + if ($expectation->test($compare)) { + return $this->pass(sprintf( + $message, + $expectation->overlayMessage($compare, $this->reporter->getDumper()))); + } else { + return $this->fail(sprintf( + $message, + $expectation->overlayMessage($compare, $this->reporter->getDumper()))); + } + } + + /** + * Uses a stack trace to find the line of an assertion. + * @return string Line number of first assert* + * method embedded in format string. + * @access public + */ + function getAssertionLine() { + $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip')); + return $trace->traceMethod(); + } + + /** + * Sends a formatted dump of a variable to the + * test suite for those emergency debugging + * situations. + * @param mixed $variable Variable to display. + * @param string $message Message to display. + * @return mixed The original variable. + * @access public + */ + function dump($variable, $message = false) { + $dumper = $this->reporter->getDumper(); + $formatted = $dumper->dump($variable); + if ($message) { + $formatted = $message . "\n" . $formatted; + } + $this->reporter->paintFormattedMessage($formatted); + return $variable; + } + + /** + * Accessor for the number of subtests including myelf. + * @return integer Number of test cases. + * @access public + */ + function getSize() { + return 1; + } +} + +/** + * Helps to extract test cases automatically from a file. + * @package SimpleTest + * @subpackage UnitTester + */ +class SimpleFileLoader { + + /** + * Builds a test suite from a library of test cases. + * The new suite is composed into this one. + * @param string $test_file File name of library with + * test case classes. + * @return TestSuite The new test suite. + * @access public + */ + function load($test_file) { + $existing_classes = get_declared_classes(); + $existing_globals = get_defined_vars(); + include_once($test_file); + $new_globals = get_defined_vars(); + $this->makeFileVariablesGlobal($existing_globals, $new_globals); + $new_classes = array_diff(get_declared_classes(), $existing_classes); + if (empty($new_classes)) { + $new_classes = $this->scrapeClassesFromFile($test_file); + } + $classes = $this->selectRunnableTests($new_classes); + return $this->createSuiteFromClasses($test_file, $classes); + } + + /** + * Imports new variables into the global namespace. + * @param hash $existing Variables before the file was loaded. + * @param hash $new Variables after the file was loaded. + * @access private + */ + protected function makeFileVariablesGlobal($existing, $new) { + $globals = array_diff(array_keys($new), array_keys($existing)); + foreach ($globals as $global) { + $GLOBALS[$global] = $new[$global]; + } + } + + /** + * Lookup classnames from file contents, in case the + * file may have been included before. + * Note: This is probably too clever by half. Figuring this + * out after a failed test case is going to be tricky for us, + * never mind the user. A test case should not be included + * twice anyway. + * @param string $test_file File name with classes. + * @access private + */ + protected function scrapeClassesFromFile($test_file) { + preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi', + file_get_contents($test_file), + $matches ); + return $matches[1]; + } + + /** + * Calculates the incoming test cases. Skips abstract + * and ignored classes. + * @param array $candidates Candidate classes. + * @return array New classes which are test + * cases that shouldn't be ignored. + * @access public + */ + function selectRunnableTests($candidates) { + $classes = array(); + foreach ($candidates as $class) { + if (TestSuite::getBaseTestCase($class)) { + $reflection = new SimpleReflection($class); + if ($reflection->isAbstract()) { + SimpleTest::ignore($class); + } else { + $classes[] = $class; + } + } + } + return $classes; + } + + /** + * Builds a test suite from a class list. + * @param string $title Title of new group. + * @param array $classes Test classes. + * @return TestSuite Group loaded with the new + * test cases. + * @access public + */ + function createSuiteFromClasses($title, $classes) { + if (count($classes) == 0) { + $suite = new BadTestSuite($title, "No runnable test cases in [$title]"); + return $suite; + } + SimpleTest::ignoreParentsIfIgnored($classes); + $suite = new TestSuite($title); + foreach ($classes as $class) { + if (! SimpleTest::isIgnored($class)) { + $suite->add($class); + } + } + return $suite; + } +} + +/** + * This is a composite test class for combining + * test cases and other RunnableTest classes into + * a group test. + * @package SimpleTest + * @subpackage UnitTester + */ +class TestSuite { + private $label; + private $test_cases; + + /** + * Sets the name of the test suite. + * @param string $label Name sent at the start and end + * of the test. + * @access public + */ + function TestSuite($label = false) { + $this->label = $label; + $this->test_cases = array(); + } + + /** + * Accessor for the test name for subclasses. If the suite + * wraps a single test case the label defaults to the name of that test. + * @return string Name of the test. + * @access public + */ + function getLabel() { + if (! $this->label) { + return ($this->getSize() == 1) ? + get_class($this->test_cases[0]) : get_class($this); + } else { + return $this->label; + } + } + + /** + * Adds a test into the suite by instance or class. The class will + * be instantiated if it's a test suite. + * @param SimpleTestCase $test_case Suite or individual test + * case implementing the + * runnable test interface. + * @access public + */ + function add($test_case) { + if (! is_string($test_case)) { + $this->test_cases[] = $test_case; + } elseif (TestSuite::getBaseTestCase($test_case) == 'testsuite') { + $this->test_cases[] = new $test_case(); + } else { + $this->test_cases[] = $test_case; + } + } + + /** + * Builds a test suite from a library of test cases. + * The new suite is composed into this one. + * @param string $test_file File name of library with + * test case classes. + * @access public + */ + function addFile($test_file) { + $extractor = new SimpleFileLoader(); + $this->add($extractor->load($test_file)); + } + + /** + * Delegates to a visiting collector to add test + * files. + * @param string $path Path to scan from. + * @param SimpleCollector $collector Directory scanner. + * @access public + */ + function collect($path, $collector) { + $collector->collect($this, $path); + } + + /** + * Invokes run() on all of the held test cases, instantiating + * them if necessary. + * @param SimpleReporter $reporter Current test reporter. + * @access public + */ + function run($reporter) { + $reporter->paintGroupStart($this->getLabel(), $this->getSize()); + for ($i = 0, $count = count($this->test_cases); $i < $count; $i++) { + if (is_string($this->test_cases[$i])) { + $class = $this->test_cases[$i]; + $test = new $class(); + $test->run($reporter); + unset($test); + } else { + $this->test_cases[$i]->run($reporter); + } + } + $reporter->paintGroupEnd($this->getLabel()); + return $reporter->getStatus(); + } + + /** + * Number of contained test cases. + * @return integer Total count of cases in the group. + * @access public + */ + function getSize() { + $count = 0; + foreach ($this->test_cases as $case) { + if (is_string($case)) { + if (! SimpleTest::isIgnored($case)) { + $count++; + } + } else { + $count += $case->getSize(); + } + } + return $count; + } + + /** + * Test to see if a class is derived from the + * SimpleTestCase class. + * @param string $class Class name. + * @access public + */ + static function getBaseTestCase($class) { + while ($class = get_parent_class($class)) { + $class = strtolower($class); + if ($class == 'simpletestcase' || $class == 'testsuite') { + return $class; + } + } + return false; + } +} + +/** + * This is a failing group test for when a test suite hasn't + * loaded properly. + * @package SimpleTest + * @subpackage UnitTester + */ +class BadTestSuite { + private $label; + private $error; + + /** + * Sets the name of the test suite and error message. + * @param string $label Name sent at the start and end + * of the test. + * @access public + */ + function BadTestSuite($label, $error) { + $this->label = $label; + $this->error = $error; + } + + /** + * Accessor for the test name for subclasses. + * @return string Name of the test. + * @access public + */ + function getLabel() { + return $this->label; + } + + /** + * Sends a single error to the reporter. + * @param SimpleReporter $reporter Current test reporter. + * @access public + */ + function run($reporter) { + $reporter->paintGroupStart($this->getLabel(), $this->getSize()); + $reporter->paintFail('Bad TestSuite [' . $this->getLabel() . + '] with error [' . $this->error . ']'); + $reporter->paintGroupEnd($this->getLabel()); + return $reporter->getStatus(); + } + + /** + * Number of contained test cases. Always zero. + * @return integer Total count of cases in the group. + * @access public + */ + function getSize() { + return 0; + } +} +?> diff --git a/application/libraries/simpletest/tidy_parser.php b/application/libraries/simpletest/tidy_parser.php new file mode 100644 index 00000000000..3d8b4b2ac7d --- /dev/null +++ b/application/libraries/simpletest/tidy_parser.php @@ -0,0 +1,382 @@ +free(); + } + + /** + * Frees up any references so as to allow the PHP garbage + * collection from unset() to work. + */ + private function free() { + unset($this->page); + $this->forms = array(); + $this->labels = array(); + } + + /** + * This builder is only available if the 'tidy' extension is loaded. + * @return boolean True if available. + */ + function can() { + return extension_loaded('tidy'); + } + + /** + * Reads the raw content the page using HTML Tidy. + * @param $response SimpleHttpResponse Fetched response. + * @return SimplePage Newly parsed page. + */ + function parse($response) { + $this->page = new SimplePage($response); + $tidied = tidy_parse_string($input = $this->insertGuards($response->getContent()), + array('output-xml' => false, 'wrap' => '0', 'indent' => 'no'), + 'latin1'); + $this->walkTree($tidied->html()); + $this->attachLabels($this->widgets_by_id, $this->labels); + $this->page->setForms($this->forms); + $page = $this->page; + $this->free(); + return $page; + } + + /** + * Stops HTMLTidy stripping content that we wish to preserve. + * @param string The raw html. + * @return string The html with guard tags inserted. + */ + private function insertGuards($html) { + return $this->insertEmptyTagGuards($this->insertTextareaSimpleWhitespaceGuards($html)); + } + + /** + * Removes the extra content added during the parse stage + * in order to preserve content we don't want stripped + * out by HTMLTidy. + * @param string The raw html. + * @return string The html with guard tags removed. + */ + private function stripGuards($html) { + return $this->stripTextareaWhitespaceGuards($this->stripEmptyTagGuards($html)); + } + + /** + * HTML tidy strips out empty tags such as