]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/SugarTestHelper.php
Release 6.5.9
[Github/sugarcrm.git] / tests / SugarTestHelper.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5  * 
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.
12  * 
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
16  * details.
17  * 
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
21  * 02110-1301 USA.
22  * 
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.
25  * 
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.
29  * 
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  ********************************************************************************/
36
37
38 if(!defined('sugarEntry')) define('sugarEntry', true);
39
40 set_include_path(
41     dirname(__FILE__) . PATH_SEPARATOR .
42     dirname(__FILE__) . '/..' . PATH_SEPARATOR .
43     get_include_path()
44 );
45
46 // constant to indicate that we are running tests
47 if (!defined('SUGAR_PHPUNIT_RUNNER'))
48     define('SUGAR_PHPUNIT_RUNNER', true);
49
50 // initialize the various globals we use
51 global $sugar_config, $db, $fileName, $current_user, $locale, $current_language;
52
53 if ( !isset($_SERVER['HTTP_USER_AGENT']) )
54     // we are probably running tests from the command line
55     $_SERVER['HTTP_USER_AGENT'] = 'cli';
56
57 // move current working directory
58 chdir(dirname(__FILE__) . '/..');
59
60 require_once('include/entryPoint.php');
61
62 require_once('include/utils/layout_utils.php');
63
64 $GLOBALS['db'] = DBManagerFactory::getInstance();
65
66 $current_language = $sugar_config['default_language'];
67 // disable the SugarLogger
68 $sugar_config['logger']['level'] = 'fatal';
69
70 $GLOBALS['sugar_config']['default_permissions'] = array (
71                 'dir_mode' => 02770,
72                 'file_mode' => 0777,
73                 'chown' => '',
74                 'chgrp' => '',
75         );
76
77 $GLOBALS['js_version_key'] = 'testrunner';
78
79 if ( !isset($_SERVER['SERVER_SOFTWARE']) )
80     $_SERVER["SERVER_SOFTWARE"] = 'PHPUnit';
81
82 // helps silence the license checking when running unit tests.
83 $_SESSION['VALIDATION_EXPIRES_IN'] = 'valid';
84
85 $GLOBALS['startTime'] = microtime(true);
86
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();
94
95 // mark that we got by the admin wizard already
96 $focus = new Administration();
97 $focus->retrieveSettings();
98 $focus->saveSetting('system','adminwizard',1);
99
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 'SugarTestRelationshipUtilities.php';
122 require_once 'SugarTestSugarEmailAddressUtilities.php';
123
124 $GLOBALS['db']->commit();
125
126 // define our testcase subclass
127 class Sugar_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase
128 {
129     protected $backupGlobals = FALSE;
130
131     protected $useOutputBuffering = true;
132
133     protected function assertPreConditions()
134     {
135         if(isset($GLOBALS['log'])) {
136             $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
137         }
138         SugarCache::instance()->flush();
139     }
140
141     protected function assertPostConditions() {
142         if(!empty($_REQUEST)) {
143             foreach(array_keys($_REQUEST) as $k) {
144                         unset($_REQUEST[$k]);
145                     }
146         }
147
148         if(!empty($_POST)) {
149             foreach(array_keys($_POST) as $k) {
150                         unset($_POST[$k]);
151                     }
152         }
153
154         if(!empty($_GET)) {
155             foreach(array_keys($_GET) as $k) {
156                         unset($_GET[$k]);
157                     }
158         }
159         if(isset($GLOBALS['log'])) {
160             $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
161         }
162         // reset error handler in case somebody set it
163         restore_error_handler();
164     }
165
166     public static function tearDownAfterClass()
167     {
168         unset($GLOBALS['disable_date_format']);
169         unset($GLOBALS['saving_relationships']);
170         unset($GLOBALS['updating_relationships']);
171         $GLOBALS['timedate']->clearCache();
172     }
173 }
174
175 // define output testcase subclass
176 class Sugar_PHPUnit_Framework_OutputTestCase extends PHPUnit_Extensions_OutputTestCase
177 {
178     protected $backupGlobals = FALSE;
179
180     protected $_notRegex;
181     protected $_outputCheck;
182
183     protected function assertPreConditions()
184     {
185         if(isset($GLOBALS['log'])) {
186             $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
187         }
188         SugarCache::instance()->flush();
189     }
190
191     protected function assertPostConditions() {
192         if(!empty($_REQUEST)) {
193             foreach(array_keys($_REQUEST) as $k) {
194                         unset($_REQUEST[$k]);
195                     }
196         }
197
198         if(!empty($_POST)) {
199             foreach(array_keys($_POST) as $k) {
200                         unset($_POST[$k]);
201                     }
202         }
203
204         if(!empty($_GET)) {
205             foreach(array_keys($_GET) as $k) {
206                         unset($_GET[$k]);
207                     }
208         }
209         if(isset($GLOBALS['log'])) {
210             $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
211         }
212     }
213
214     protected function NotRegexCallback($output)
215     {
216         if(empty($this->_notRegex)) {
217             return true;
218         }
219         $this->assertNotRegExp($this->_notRegex, $output);
220         return true;
221     }
222
223     public function setOutputCheck($callback)
224     {
225         if (!is_callable($callback)) {
226             throw new PHPUnit_Framework_Exception;
227         }
228
229         $this->_outputCheck = $callback;
230     }
231
232     protected function runTest()
233     {
234                 $testResult = parent::runTest();
235         if($this->_outputCheck) {
236             $this->assertTrue(call_user_func($this->_outputCheck, $this->output));
237         }
238         return $testResult;
239     }
240
241     public function expectOutputNotRegex($expectedRegex)
242     {
243         if (is_string($expectedRegex) || is_null($expectedRegex)) {
244             $this->_notRegex = $expectedRegex;
245         }
246
247         $this->setOutputCheck(array($this, "NotRegexCallback"));
248     }
249
250 }
251
252 // define a mock logger interface; used for capturing logging messages emited
253 // the test suite
254 class SugarMockLogger
255 {
256         private $_messages = array();
257
258         public function __call($method, $message)
259         {
260                 $this->messages[] = strtoupper($method) . ': ' . $message[0];
261         }
262
263         public function getLastMessage()
264         {
265                 return end($this->messages);
266         }
267
268         public function getMessageCount()
269         {
270                 return count($this->messages);
271         }
272 }
273
274 require_once('ModuleInstall/ModuleInstaller.php');
275
276 /**
277  * Own exception for SugarTestHelper class
278  *
279  * @author mgusev@sugarcrm.com
280  */
281 class SugarTestHelperException extends PHPUnit_Framework_Exception
282 {
283
284 }
285
286 /**
287  * Helper for initialization of global variables of SugarCRM
288  *
289  * @author mgusev@sugarcrm.com
290  */
291 class SugarTestHelper
292 {
293     /**
294      * @var array array of registered vars. It allows helper to unregister them on tearDown
295      */
296     protected static $registeredVars = array();
297
298     /**
299      * @var array array of global vars. They are storing on init one time and restoring in global scope each tearDown
300      */
301     protected static $initVars = array(
302         'GLOBALS' => array()
303     );
304
305     /**
306      * @var array of system preference of SugarCRM as theme etc. They are storing on init one time and restoring each tearDown
307      */
308     protected static $systemVars = array();
309
310     /**
311      * @var array of modules which we should refresh on tearDown.
312      */
313     protected static $cleanModules = array();
314
315     /**
316      * @var bool is SugarTestHelper inited or not. Just to skip initialization on the second and others call of init method
317      */
318     protected static $isInited = false;
319
320     /**
321      * All methods are static because of it we disable constructor
322      */
323     private function __construct()
324     {
325     }
326
327     /**
328      * All methods are static because of it we disable clone
329      */
330     private function __clone()
331     {
332     }
333
334     /**
335      * Initialization of main variables of SugarCRM in global scope
336      *
337      * @static
338      */
339     public static function init()
340     {
341         if (self::$isInited == true)
342         {
343             return true;
344         }
345
346         // initialization & backup of sugar_config
347         self::$initVars['GLOBALS']['sugar_config'] = null;
348         if ($GLOBALS['sugar_config'])
349         {
350             self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
351         }
352         if (self::$initVars['GLOBALS']['sugar_config'] == false)
353         {
354             global $sugar_config;
355             if (is_file('config.php'))
356             {
357                 require_once('config.php');
358             }
359             if (is_file('config_override.php'))
360             {
361                 require_once('config_override.php');
362             }
363             self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
364         }
365
366         // backup of current_language
367         self::$initVars['GLOBALS']['current_language'] = 'en_us';
368         if (isset($sugar_config['current_language']))
369         {
370             self::$initVars['GLOBALS']['current_language'] = $sugar_config['current_language'];
371         }
372         if (isset($GLOBALS['current_language']))
373         {
374             self::$initVars['GLOBALS']['current_language'] = $GLOBALS['current_language'];
375         }
376         $GLOBALS['current_language'] = self::$initVars['GLOBALS']['current_language'];
377
378         // backup of reload_vardefs
379         self::$initVars['GLOBALS']['reload_vardefs'] = null;
380         if (isset($GLOBALS['reload_vardefs']))
381         {
382             self::$initVars['GLOBALS']['reload_vardefs'] = $GLOBALS['reload_vardefs'];
383         }
384
385         // backup of locale
386         self::$initVars['GLOBALS']['locale'] = null;
387         if (isset($GLOBALS['locale']))
388         {
389             self::$initVars['GLOBALS']['locale'] = $GLOBALS['locale'];
390         }
391         if (self::$initVars['GLOBALS']['locale'] == false)
392         {
393             self::$initVars['GLOBALS']['locale'] = new Localization();
394         }
395
396         // backup of service_object
397         self::$initVars['GLOBALS']['service_object'] = null;
398         if (isset($GLOBALS['service_object']))
399         {
400             self::$initVars['GLOBALS']['service_object'] = $GLOBALS['service_object'];
401         }
402
403         // backup of SugarThemeRegistry
404         self::$systemVars['SugarThemeRegistry'] = SugarThemeRegistry::current();
405
406         self::$isInited = true;
407     }
408
409     /**
410      * Checking is there helper for variable or not
411      *
412      * @static
413      * @param string $varName name of global variable of SugarCRM
414      * @return bool is there helper for a variable or not
415      * @throws SugarTestHelperException fired when there is no implementation of helper for a variable
416      */
417     protected static function checkHelper($varName)
418     {
419         if (method_exists(__CLASS__, 'setUp_' . $varName) == false)
420         {
421             throw new SugarTestHelperException('setUp for $' . $varName . ' is not implemented. ' . __CLASS__ . '::setUp_' . $varName);
422         }
423     }
424
425     /**
426      * Entry point for setup of global variable
427      *
428      * @static
429      * @param string $varName name of global variable of SugarCRM
430      * @param array $params some parameters for helper. For example for $mod_strings or $current_user
431      * @return bool is variable setuped or not
432      */
433     public static function setUp($varName, $params = array())
434     {
435         self::init();
436         self::checkHelper($varName);
437         return call_user_func(__CLASS__ . '::setUp_' . $varName, $params);
438     }
439
440     /**
441      * Clean up all registered variables and restore $initVars and $systemVars
442      * @static
443      * @return bool status of tearDown
444      */
445     public static function tearDown()
446     {
447         self::init();
448         foreach(self::$registeredVars as $varName => $isCalled)
449         {
450             if ($isCalled)
451             {
452                 unset(self::$registeredVars[$varName]);
453                 if (method_exists(__CLASS__, 'tearDown_' . $varName))
454                 {
455                     call_user_func(__CLASS__ . '::tearDown_' . $varName, array());
456                 }
457                 elseif (isset($GLOBALS[$varName]))
458                 {
459                     unset($GLOBALS[$varName]);
460                 }
461             }
462         }
463
464         // Restoring of system variables
465         foreach(self::$initVars as $scope => $vars)
466         {
467             foreach ($vars as $name => $value)
468             {
469                 $GLOBALS[$scope][$name] = $value;
470             }
471         }
472
473         // Restoring of theme
474         SugarThemeRegistry::set(self::$systemVars['SugarThemeRegistry']->dirName);
475         SugarCache::$isCacheReset = false;
476         return true;
477     }
478
479     /**
480      * Registration of $current_user in global scope
481      *
482      * @static
483      * @param array $params parameters for SugarTestUserUtilities::createAnonymousUser method
484      * @return bool is variable setuped or not
485      */
486     protected static function setUp_current_user(array $params)
487     {
488         self::$registeredVars['current_user'] = true;
489         $GLOBALS['current_user'] = call_user_func_array('SugarTestUserUtilities::createAnonymousUser', $params);
490         return true;
491     }
492
493     /**
494      * Removal of $current_user from global scope
495      *
496      * @static
497      * @return bool is variable removed or not
498      */
499     protected static function tearDown_current_user()
500     {
501         SugarTestUserUtilities::removeAllCreatedAnonymousUsers();
502         unset($GLOBALS['current_user']);
503         return true;
504     }
505
506     /**
507      * Registration of $beanList in global scope
508      *
509      * @static
510      * @return bool is variable setuped or not
511      */
512     protected static function setUp_beanList()
513     {
514         self::$registeredVars['beanList'] = true;
515         global $beanList;
516         require('include/modules.php');
517         return true;
518     }
519
520     /**
521      * Registration of $beanFiles in global scope
522      *
523      * @static
524      * @return bool is variable setuped or not
525      */
526     protected static function setUp_beanFiles()
527     {
528         self::$registeredVars['beanFiles'] = true;
529         global $beanFiles;
530         require('include/modules.php');
531         return true;
532     }
533
534     /**
535      * Registration of $moduleList in global scope
536      *
537      * @static
538      * @return bool is variable setuped or not
539      */
540     protected static function setUp_moduleList()
541     {
542         self::$registeredVars['moduleList'] = true;
543         global $moduleList;
544         require('include/modules.php');
545         return true;
546     }
547
548     /**
549      * Reinitialization of $moduleList in global scope because we can't unset that variable
550      *
551      * @static
552      * @return bool is variable setuped or not
553      */
554     protected static function tearDown_moduleList()
555     {
556         return self::setUp_moduleList();
557     }
558
559     /**
560      * Registration of $modListHeader in global scope
561      *
562      * @static
563      * @return bool is variable setuped or not
564      */
565     protected static function setUp_modListHeader()
566     {
567         self::$registeredVars['modListHeader'] = true;
568         if (isset($GLOBALS['current_user']) == false)
569         {
570             self::setUp_current_user(array(
571                 true,
572                 1
573             ));
574         }
575         $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
576         return true;
577     }
578
579     /**
580      * Registration of $app_strings in global scope
581      *
582      * @static
583      * @return bool is variable setuped or not
584      */
585     protected static function setUp_app_strings()
586     {
587         self::$registeredVars['app_strings'] = true;
588         $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']);
589         return true;
590     }
591
592     /**
593      * Registration of $app_list_strings in global scope
594      *
595      * @static
596      * @return bool is variable setuped or not
597      */
598     protected static function setUp_app_list_strings()
599     {
600         self::$registeredVars['app_list_strings'] = true;
601         $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']);
602         return true;
603     }
604
605     /**
606      * Registration of $timedate in global scope
607      *
608      * @static
609      * @return bool is variable setuped or not
610      */
611     protected static function setUp_timedate()
612     {
613         self::$registeredVars['timedate'] = true;
614         $GLOBALS['timedate'] = TimeDate::getInstance();
615         return true;
616     }
617
618     /**
619      * Removal of $timedate from global scope
620      *
621      * @static
622      * @return bool is variable removed or not
623      */
624     protected static function tearDown_timedate()
625     {
626         $GLOBALS['timedate']->clearCache();
627         return true;
628     }
629
630     /**
631      * Registration of $mod_strings in global scope
632      *
633      * @static
634      * @param array $params parameters for return_module_language function
635      * @return bool is variable setuped or not
636      */
637     protected static function setUp_mod_strings(array $params)
638     {
639         self::$registeredVars['mod_strings'] = true;
640         $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $params[0]);
641         return true;
642     }
643
644     /**
645      * Registration of $dictionary in global scope
646      *
647      * @static
648      * @return bool is variable setuped or not
649      */
650     protected static function setUp_dictionary()
651     {
652         self::setUp('beanFiles');
653         self::setUp('beanList');
654         self::$registeredVars['dictionary'] = true;
655
656         global $dictionary;
657         $dictionary = array();
658         $moduleInstaller = new ModuleInstaller();
659         $moduleInstaller->silent = true;
660         $moduleInstaller->rebuild_tabledictionary();
661         require 'modules/TableDictionary.php';
662
663         foreach($GLOBALS['beanList'] as $k => $v)
664         {
665             VardefManager::loadVardef($k, $v);
666         }
667         return true;
668     }
669
670     /**
671      * Reinitialization of $dictionary in global scope because we can't unset that variable
672      *
673      * @static
674      * @return bool is variable setuped or not
675      */
676     protected static function tearDown_dictionary()
677     {
678         return self::setUp_dictionary();
679     }
680
681     /**
682      * Cleaning caches and refreshing vardefs
683      *
684      * @static
685      * @param string $lhs_module left module from relation
686      * @param string $rhs_module right module from relation
687      * @return bool are caches refreshed or not
688      */
689     protected static function setUp_relation(array $params)
690     {
691         if (empty($params[0]) || empty($params[1]))
692         {
693             throw new SugarTestHelperException('setUp("relation") requires two parameters');
694         }
695         list($lhs_module, $rhs_module) = $params;
696         self::$registeredVars['relation'] = true;
697         self::$cleanModules[] = $lhs_module;
698
699         LanguageManager::clearLanguageCache($lhs_module);
700         if ($lhs_module != $rhs_module)
701         {
702             self::$cleanModules[] = $rhs_module;
703             LanguageManager::clearLanguageCache($rhs_module);
704         }
705
706         self::setUp('dictionary');
707
708         VardefManager::$linkFields = array();
709         VardefManager::clearVardef();
710         VardefManager::refreshVardefs($lhs_module, BeanFactory::getObjectName($lhs_module));
711         if ($lhs_module != $rhs_module)
712         {
713             VardefManager::refreshVardefs($rhs_module, BeanFactory::getObjectName($rhs_module));
714         }
715         SugarRelationshipFactory::rebuildCache();
716
717         return true;
718     }
719
720     /**
721      * Doing the same things like setUp but for initialized list of modules
722      *
723      * @static
724      * @return bool are caches refreshed or not
725      */
726     protected static function tearDown_relation()
727     {
728         SugarRelationshipFactory::deleteCache();
729
730         $modules = array_unique(self::$cleanModules);
731         foreach ($modules as $module)
732         {
733             LanguageManager::clearLanguageCache($module);
734         }
735
736         self::tearDown('dictionary');
737
738         VardefManager::$linkFields = array();
739         VardefManager::clearVardef();
740         foreach($modules as $module)
741         {
742             VardefManager::refreshVardefs($module, BeanFactory::getBeanName($module));
743         }
744         SugarRelationshipFactory::rebuildCache();
745
746         self::$cleanModules = array();
747         return true;
748     }
749 }