2 /*********************************************************************************
3 * SugarCRM Community Edition is a customer relationship management program developed by
4 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6 * This program is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Affero General Public License version 3 as published by the
8 * Free Software Foundation with the addition of the following permission added
9 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
18 * You should have received a copy of the GNU Affero General Public License along with
19 * this program; if not, see http://www.gnu.org/licenses or write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU Affero General Public License version 3.
30 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31 * these Appropriate Legal Notices must retain the display of the "Powered by
32 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33 * technical reasons, the Appropriate Legal Notices must display the words
34 * "Powered by SugarCRM".
35 ********************************************************************************/
38 if(!defined('sugarEntry')) define('sugarEntry', true);
41 dirname(__FILE__) . PATH_SEPARATOR .
42 dirname(__FILE__) . '/..' . PATH_SEPARATOR .
46 // constant to indicate that we are running tests
47 if (!defined('SUGAR_PHPUNIT_RUNNER'))
48 define('SUGAR_PHPUNIT_RUNNER', true);
50 // initialize the various globals we use
51 global $sugar_config, $db, $fileName, $current_user, $locale, $current_language;
53 if ( !isset($_SERVER['HTTP_USER_AGENT']) )
54 // we are probably running tests from the command line
55 $_SERVER['HTTP_USER_AGENT'] = 'cli';
57 // move current working directory
58 chdir(dirname(__FILE__) . '/..');
60 require_once('include/entryPoint.php');
62 require_once('include/utils/layout_utils.php');
64 $GLOBALS['db'] = DBManagerFactory::getInstance();
66 $current_language = $sugar_config['default_language'];
67 // disable the SugarLogger
68 $sugar_config['logger']['level'] = 'fatal';
70 $GLOBALS['sugar_config']['default_permissions'] = array (
77 $GLOBALS['js_version_key'] = 'testrunner';
79 if ( !isset($_SERVER['SERVER_SOFTWARE']) )
80 $_SERVER["SERVER_SOFTWARE"] = 'PHPUnit';
82 // helps silence the license checking when running unit tests.
83 $_SESSION['VALIDATION_EXPIRES_IN'] = 'valid';
85 $GLOBALS['startTime'] = microtime(true);
87 // clean out the cache directory
88 require_once('modules/Administration/QuickRepairAndRebuild.php');
89 $repair = new RepairAndClear();
90 $repair->module_list = array();
91 $repair->show_output = false;
92 $repair->clearJsLangFiles();
93 $repair->clearJsFiles();
95 // mark that we got by the admin wizard already
96 $focus = new Administration();
97 $focus->retrieveSettings();
98 $focus->saveSetting('system','adminwizard',1);
100 // include the other test tools
101 require_once 'SugarTestObjectUtilities.php';
102 require_once 'SugarTestProjectUtilities.php';
103 require_once 'SugarTestProjectTaskUtilities.php';
104 require_once 'SugarTestUserUtilities.php';
105 require_once 'SugarTestEmailAddressUtilities.php';
106 require_once 'SugarTestLangPackCreator.php';
107 require_once 'SugarTestThemeUtilities.php';
108 require_once 'SugarTestContactUtilities.php';
109 require_once 'SugarTestEmailUtilities.php';
110 require_once 'SugarTestCampaignUtilities.php';
111 require_once 'SugarTestLeadUtilities.php';
112 require_once 'SugarTestStudioUtilities.php';
113 require_once 'SugarTestMeetingUtilities.php';
114 require_once 'SugarTestCallUtilities.php';
115 require_once 'SugarTestAccountUtilities.php';
116 require_once 'SugarTestTrackerUtility.php';
117 require_once 'SugarTestImportUtilities.php';
118 require_once 'SugarTestMergeUtilities.php';
119 require_once 'SugarTestTaskUtilities.php';
120 require_once 'SugarTestOpportunityUtilities.php';
121 require_once 'SugarTestCurrencyUtilities.php';
122 require_once 'SugarTestRelationshipUtilities.php';
123 require_once 'SugarTestSugarEmailAddressUtilities.php';
125 $GLOBALS['db']->commit();
127 // define our testcase subclass
128 class Sugar_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase
130 protected $backupGlobals = FALSE;
132 protected $useOutputBuffering = true;
134 protected function assertPreConditions()
136 if(isset($GLOBALS['log'])) {
137 $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
139 SugarCache::instance()->flush();
142 protected function assertPostConditions() {
143 if(!empty($_REQUEST)) {
144 foreach(array_keys($_REQUEST) as $k) {
145 unset($_REQUEST[$k]);
150 foreach(array_keys($_POST) as $k) {
156 foreach(array_keys($_GET) as $k) {
160 if(isset($GLOBALS['log'])) {
161 $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
163 // reset error handler in case somebody set it
164 restore_error_handler();
167 public static function tearDownAfterClass()
169 unset($GLOBALS['disable_date_format']);
170 unset($GLOBALS['saving_relationships']);
171 unset($GLOBALS['updating_relationships']);
172 $GLOBALS['timedate']->clearCache();
176 // define output testcase subclass
177 class Sugar_PHPUnit_Framework_OutputTestCase extends PHPUnit_Extensions_OutputTestCase
179 protected $backupGlobals = FALSE;
181 protected $_notRegex;
182 protected $_outputCheck;
184 protected function assertPreConditions()
186 if(isset($GLOBALS['log'])) {
187 $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
189 SugarCache::instance()->flush();
192 protected function assertPostConditions() {
193 if(!empty($_REQUEST)) {
194 foreach(array_keys($_REQUEST) as $k) {
195 unset($_REQUEST[$k]);
200 foreach(array_keys($_POST) as $k) {
206 foreach(array_keys($_GET) as $k) {
210 if(isset($GLOBALS['log'])) {
211 $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
215 protected function NotRegexCallback($output)
217 if(empty($this->_notRegex)) {
220 $this->assertNotRegExp($this->_notRegex, $output);
224 public function setOutputCheck($callback)
226 if (!is_callable($callback)) {
227 throw new PHPUnit_Framework_Exception;
230 $this->_outputCheck = $callback;
233 protected function runTest()
235 $testResult = parent::runTest();
236 if($this->_outputCheck) {
237 $this->assertTrue(call_user_func($this->_outputCheck, $this->output));
242 public function expectOutputNotRegex($expectedRegex)
244 if (is_string($expectedRegex) || is_null($expectedRegex)) {
245 $this->_notRegex = $expectedRegex;
248 $this->setOutputCheck(array($this, "NotRegexCallback"));
253 // define a mock logger interface; used for capturing logging messages emited
255 class SugarMockLogger
257 private $_messages = array();
259 public function __call($method, $message)
261 $this->messages[] = strtoupper($method) . ': ' . $message[0];
264 public function getLastMessage()
266 return end($this->messages);
269 public function getMessageCount()
271 return count($this->messages);
275 require_once('ModuleInstall/ModuleInstaller.php');
278 * Own exception for SugarTestHelper class
280 * @author mgusev@sugarcrm.com
282 class SugarTestHelperException extends PHPUnit_Framework_Exception
288 * Helper for initialization of global variables of SugarCRM
290 * @author mgusev@sugarcrm.com
292 class SugarTestHelper
295 * @var array array of registered vars. It allows helper to unregister them on tearDown
297 protected static $registeredVars = array();
300 * @var array array of global vars. They are storing on init one time and restoring in global scope each tearDown
302 protected static $initVars = array(
307 * @var array of system preference of SugarCRM as theme etc. They are storing on init one time and restoring each tearDown
309 protected static $systemVars = array();
312 * @var array of modules which we should refresh on tearDown.
314 protected static $cleanModules = array();
317 * @var bool is SugarTestHelper inited or not. Just to skip initialization on the second and others call of init method
319 protected static $isInited = false;
322 * All methods are static because of it we disable constructor
324 private function __construct()
329 * All methods are static because of it we disable clone
331 private function __clone()
336 * Initialization of main variables of SugarCRM in global scope
340 public static function init()
342 if (self::$isInited == true)
347 // initialization & backup of sugar_config
348 self::$initVars['GLOBALS']['sugar_config'] = null;
349 if ($GLOBALS['sugar_config'])
351 self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
353 if (self::$initVars['GLOBALS']['sugar_config'] == false)
355 global $sugar_config;
356 if (is_file('config.php'))
358 require_once('config.php');
360 if (is_file('config_override.php'))
362 require_once('config_override.php');
364 self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
367 // backup of current_language
368 self::$initVars['GLOBALS']['current_language'] = 'en_us';
369 if (isset($sugar_config['current_language']))
371 self::$initVars['GLOBALS']['current_language'] = $sugar_config['current_language'];
373 if (isset($GLOBALS['current_language']))
375 self::$initVars['GLOBALS']['current_language'] = $GLOBALS['current_language'];
377 $GLOBALS['current_language'] = self::$initVars['GLOBALS']['current_language'];
379 // backup of reload_vardefs
380 self::$initVars['GLOBALS']['reload_vardefs'] = null;
381 if (isset($GLOBALS['reload_vardefs']))
383 self::$initVars['GLOBALS']['reload_vardefs'] = $GLOBALS['reload_vardefs'];
387 self::$initVars['GLOBALS']['locale'] = null;
388 if (isset($GLOBALS['locale']))
390 self::$initVars['GLOBALS']['locale'] = $GLOBALS['locale'];
392 if (self::$initVars['GLOBALS']['locale'] == false)
394 self::$initVars['GLOBALS']['locale'] = new Localization();
397 // backup of service_object
398 self::$initVars['GLOBALS']['service_object'] = null;
399 if (isset($GLOBALS['service_object']))
401 self::$initVars['GLOBALS']['service_object'] = $GLOBALS['service_object'];
404 // backup of SugarThemeRegistry
405 self::$systemVars['SugarThemeRegistry'] = SugarThemeRegistry::current();
407 self::$isInited = true;
411 * Checking is there helper for variable or not
414 * @param string $varName name of global variable of SugarCRM
415 * @return bool is there helper for a variable or not
416 * @throws SugarTestHelperException fired when there is no implementation of helper for a variable
418 protected static function checkHelper($varName)
420 if (method_exists(__CLASS__, 'setUp_' . $varName) == false)
422 throw new SugarTestHelperException('setUp for $' . $varName . ' is not implemented. ' . __CLASS__ . '::setUp_' . $varName);
427 * Entry point for setup of global variable
430 * @param string $varName name of global variable of SugarCRM
431 * @param array $params some parameters for helper. For example for $mod_strings or $current_user
432 * @return bool is variable setuped or not
434 public static function setUp($varName, $params = array())
437 self::checkHelper($varName);
438 return call_user_func(__CLASS__ . '::setUp_' . $varName, $params);
442 * Clean up all registered variables and restore $initVars and $systemVars
444 * @return bool status of tearDown
446 public static function tearDown()
449 foreach(self::$registeredVars as $varName => $isCalled)
453 unset(self::$registeredVars[$varName]);
454 if (method_exists(__CLASS__, 'tearDown_' . $varName))
456 call_user_func(__CLASS__ . '::tearDown_' . $varName, array());
458 elseif (isset($GLOBALS[$varName]))
460 unset($GLOBALS[$varName]);
465 // Restoring of system variables
466 foreach(self::$initVars as $scope => $vars)
468 foreach ($vars as $name => $value)
470 $GLOBALS[$scope][$name] = $value;
474 // Restoring of theme
475 SugarThemeRegistry::set(self::$systemVars['SugarThemeRegistry']->dirName);
476 SugarCache::$isCacheReset = false;
481 * Registration of $current_user in global scope
484 * @param array $params parameters for SugarTestUserUtilities::createAnonymousUser method
485 * @return bool is variable setuped or not
487 protected static function setUp_current_user(array $params)
489 self::$registeredVars['current_user'] = true;
490 $GLOBALS['current_user'] = call_user_func_array('SugarTestUserUtilities::createAnonymousUser', $params);
495 * Removal of $current_user from global scope
498 * @return bool is variable removed or not
500 protected static function tearDown_current_user()
502 SugarTestUserUtilities::removeAllCreatedAnonymousUsers();
503 unset($GLOBALS['current_user']);
508 * Registration of $beanList in global scope
511 * @return bool is variable setuped or not
513 protected static function setUp_beanList()
515 self::$registeredVars['beanList'] = true;
517 require('include/modules.php');
522 * Registration of $beanFiles in global scope
525 * @return bool is variable setuped or not
527 protected static function setUp_beanFiles()
529 self::$registeredVars['beanFiles'] = true;
531 require('include/modules.php');
536 * Registration of $moduleList in global scope
539 * @return bool is variable setuped or not
541 protected static function setUp_moduleList()
543 self::$registeredVars['moduleList'] = true;
545 require('include/modules.php');
550 * Reinitialization of $moduleList in global scope because we can't unset that variable
553 * @return bool is variable setuped or not
555 protected static function tearDown_moduleList()
557 return self::setUp_moduleList();
561 * Registration of $modListHeader in global scope
564 * @return bool is variable setuped or not
566 protected static function setUp_modListHeader()
568 self::$registeredVars['modListHeader'] = true;
569 if (isset($GLOBALS['current_user']) == false)
571 self::setUp_current_user(array(
576 $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
581 * Registration of $app_strings in global scope
584 * @return bool is variable setuped or not
586 protected static function setUp_app_strings()
588 self::$registeredVars['app_strings'] = true;
589 $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']);
594 * Registration of $app_list_strings in global scope
597 * @return bool is variable setuped or not
599 protected static function setUp_app_list_strings()
601 self::$registeredVars['app_list_strings'] = true;
602 $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']);
607 * Registration of $timedate in global scope
610 * @return bool is variable setuped or not
612 protected static function setUp_timedate()
614 self::$registeredVars['timedate'] = true;
615 $GLOBALS['timedate'] = TimeDate::getInstance();
620 * Removal of $timedate from global scope
623 * @return bool is variable removed or not
625 protected static function tearDown_timedate()
627 $GLOBALS['timedate']->clearCache();
632 * Registration of $mod_strings in global scope
635 * @param array $params parameters for return_module_language function
636 * @return bool is variable setuped or not
638 protected static function setUp_mod_strings(array $params)
640 self::$registeredVars['mod_strings'] = true;
641 $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $params[0]);
646 * Registration of $dictionary in global scope
649 * @return bool is variable setuped or not
651 protected static function setUp_dictionary()
653 self::setUp('beanFiles');
654 self::setUp('beanList');
655 self::$registeredVars['dictionary'] = true;
658 $dictionary = array();
659 $moduleInstaller = new ModuleInstaller();
660 $moduleInstaller->silent = true;
661 $moduleInstaller->rebuild_tabledictionary();
662 require 'modules/TableDictionary.php';
664 foreach($GLOBALS['beanList'] as $k => $v)
666 VardefManager::loadVardef($k, $v);
672 * Reinitialization of $dictionary in global scope because we can't unset that variable
675 * @return bool is variable setuped or not
677 protected static function tearDown_dictionary()
679 return self::setUp_dictionary();
683 * Cleaning caches and refreshing vardefs
686 * @param string $lhs_module left module from relation
687 * @param string $rhs_module right module from relation
688 * @return bool are caches refreshed or not
690 protected static function setUp_relation(array $params)
692 if (empty($params[0]) || empty($params[1]))
694 throw new SugarTestHelperException('setUp("relation") requires two parameters');
696 list($lhs_module, $rhs_module) = $params;
697 self::$registeredVars['relation'] = true;
698 self::$cleanModules[] = $lhs_module;
700 LanguageManager::clearLanguageCache($lhs_module);
701 if ($lhs_module != $rhs_module)
703 self::$cleanModules[] = $rhs_module;
704 LanguageManager::clearLanguageCache($rhs_module);
707 self::setUp('dictionary');
709 VardefManager::$linkFields = array();
710 VardefManager::clearVardef();
711 VardefManager::refreshVardefs($lhs_module, BeanFactory::getObjectName($lhs_module));
712 if ($lhs_module != $rhs_module)
714 VardefManager::refreshVardefs($rhs_module, BeanFactory::getObjectName($rhs_module));
716 SugarRelationshipFactory::rebuildCache();
722 * Doing the same things like setUp but for initialized list of modules
725 * @return bool are caches refreshed or not
727 protected static function tearDown_relation()
729 SugarRelationshipFactory::deleteCache();
731 $modules = array_unique(self::$cleanModules);
732 foreach ($modules as $module)
734 LanguageManager::clearLanguageCache($module);
737 self::tearDown('dictionary');
739 VardefManager::$linkFields = array();
740 VardefManager::clearVardef();
741 foreach($modules as $module)
743 VardefManager::refreshVardefs($module, BeanFactory::getBeanName($module));
745 SugarRelationshipFactory::rebuildCache();
747 self::$cleanModules = array();