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