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