Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/site/app/tests/test_helper_unit.php
blob: f88f691b463b96c1dbf45d5baade19050d464665 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
<?php
/**
* Original file from http://cakephp.org/pastes/show/8803bd09150cb65cc7da63f92cdbc828
* Modifications by Justin Scott <fligtar@gmail.com>
*/

class UnitTestHelper
{
    var $previouslyCalled = array(); //called actions go here once called once
    
    /**
     * Loops through the $uses array of a Controller and mocks all used Models
     * and also allows additional methods for them to be pased via $params, (as
     * well as to set names for the generated mocks).
     *
     * @param unknown_type $Controller
     * @param mixed $testCase
     * @param unknown_type $params
     */
    function mockModels(&$Controller, &$testCase, $params = array())
    {
        if ($Controller->uses===false)
        {
            $model = Inflector::singularize($Controller->name);
            
            /**
             * If our uses array is empty CakePHP will always assume a default model.
             * So let's check if it exists.
             */
            $testCase->assertTrue(class_exists(strtolower($model)), 'Model "'.$model.'" exists');
            
            return;
        }
        
        /**
         * If we have Models to mock let's loop throw them
         */
        if (is_array($Controller->uses))
        {
            foreach ($Controller->uses as $model)
            {
                /**
                 * Check if the Models we use exist (CakePHP automatically includes them for us)
                 */
                $modelExists = $testCase->assertTrue(class_exists(strtolower($model)), 'Model "'.$model.'" exists');
                
                if ($modelExists)
                {
                    /**
                     * If we have customized Model Mocks to generate, set the vars for it
                     */
                    if (isset($params[$model]['name']))
                        $class = $params[$model]['name'];
                    else 
                        $class = false;
    
                    if (isset($params[$model]['methods']))
                        $methods = $params[$model]['methods'];
                    else 
                        $methods = false;
                    
                    /**
                     * Create the Model Mock
                     */
                    Mock::generate($model, $class, $methods);
                    
                    /**
                     * Add the Mock to the Controller
                     */
                    $mockModel = 'Mock'.$model;
                    $Controller->{$model} =& new $mockModel;
                }
            }
        }
    }

    /**
     * Loads the components for a controller
     * @param unknown_type $controller
     * @param unkown-type $testCase
     */
    function mockComponents(&$controller, &$testCase) {
        if(is_array($controller->components)) {
            foreach($controller->components as $component) {
                 loadComponent($component);
                 $componentClass = $component.'Component';
                 $testCase->assertTrue(class_exists($componentClass), 'Component "'.$component.'" exists');
                 Mock::generate($componentClass, false,  false);
                 $mockComponent = 'Mock'.$componentClass;
                 $controller->{$component} =& new $mockComponent;
                 /*if(method_exists($controller->{$component}, 'startup')) {
                     $controller->{$component}->startup($controller);
                     call_user_func(array($componentClass, 'startup'), $controller);
                 }*/
            }
        }
    }
    
    /**
     * Returns a fully initialized Controller
     *
     * @param unknown_type $controller
     * @param unknown_type $testCase
     * @param unknown_type $app
     * @return unknown
     */
    function getController($controller, &$testCase, $app = 'app')
    {
        $this->loadController($controller, $testCase, $app);
        
        $className = $controller.'Controller';
        
        // intercept flash() and redirect() calls from Controller
        if (!class_exists('Mock'.$className)) {
            eval('  class Mock'.$className.' extends '.$className.' {
                        function flash($msg,$url,$pause=1) {}
                        function redirect($url,$status=null) {}
                    }');
        }
        
        $mockControllerName = 'Mock'.$className;
        
        $Controller =& new $mockControllerName();
        $Controller->constructClasses();
        return $Controller;
    }
    
    /**
     * Calls a Controller action and returns the function return value or the output
     * if existing.
     *
     * @param object $Controller
     * @param string $action
     * @param object $testCase
     * @param array $params     
     * @param string $app
     * @return mixed
     */
    function callControllerAction(&$Controller, $action, &$testCase, $params = array(), $app = 'app')
    {        
        $methods = get_class_methods($Controller);
        
        //Cut down on spam
        if (!array_key_exists($Controller->name, $this->previouslyCalled) || (array_key_exists($Controller->name, $this->previouslyCalled) && !in_array($action, $this->previouslyCalled[$Controller->name]))) {
            $testCase->assertTrue(in_array($action, $methods), $Controller->name.'Controller::'.$action.'() exists');
            $this->previouslyCalled[$Controller->name][] = $action;
        }

        if (!is_array($params))
            $params = array();
            
        $Controller->action = $action;

        /**
         * By creating our own AppError class we can catch Object::cakeError() calls and
         * output them so we can throw an exception later on!
         */
        if (!class_exists('AppError'))
        {
            eval('class AppError
                  {
                      function AppError($method)
                      {
                           echo "error:$method";
                      }
                  }');
        }
        
        ob_start();
        $return = call_user_func_array(array(&$Controller, $action), $params);
        $output = @ob_get_clean();
        
        if ($Controller->autoRender)
        {
            ob_start();
            $Controller->render();
            $output = @ob_get_clean();
        }

        /*
         * @TODO This is ugly:
         * Print SimpleTest error messages if there were any in the output.
         */
        $outputarray = explode("\n", $output);
        $outputarray = preg_grep('/^<div class="(pass|fail)">.*<\/div>$/', $outputarray);
        foreach ($outputarray as $errorline)
            print $errorline."\n";
        
        /**
         * When running our TestCase rendering an action might causes some error notices
         * from the Sessions object that is trying to send headers.
         * 
         * Since there is nothing we can do to prevent those, we are going to filter them
         * out and add the $realErrors back into the queue later on.
         */
        $queue = &SimpleTest::getContext()->get('SimpleErrorQueue');
        $realErrors = array();
       
        while ($error = $queue->extract())
        {
            if (!preg_match('/headers already sent/i', $error[1]))
            {
                $realErrors[] = $error;
                break;
            }
        }
        
        /**
         * Add the real errors back to the queue
         */
        foreach ($realErrors as $error)
        {
            call_user_func_array(array(&$queue, 'add'), $error);
        }
        
        $match = null;
        if (preg_match('/^error:(.+)$/', $output, $match))
        {
            trigger_error('CakePHP Error: '.$match[1], E_USER_WARNING);
        }
        
        if (empty($output))
            return $return;
        else 
            return $output;
    }
  
    /**
     * Loads a controller named $controller. If the User passes an instance of the $testCase
     * that this call is being made from, an automatic assertion for the existence of this
     * Controller happens.
     *
     * @param string $controller
     * @param object $testCase
     * @param string $app
     */
    function loadController($controller, &$testCase, $app = 'app')
    {
        // do not try to load a "dummy" controller.
        if ($controller == 'Dummy') return;
        
        $controllerFile = CONTROLLERS.strtolower($controller).'_controller.php';
        $controllerExists = file_exists($controllerFile);

        $testCase->assertTrue($controllerExists, 'Load Controller "'.$controller.'Controller"');

        if ($controllerExists)
            loadController($controller);
    }

    /**
     * Log ourselves in (i.e. mock the session component results)
     */
    function login(&$controller) {
        $userdata = array(
                    'id' => 5,
                    'email' => 'nobody@mozilla.org',
                    'password' => '098f6bcd4621d373cade4e832627b4f6',
                    'firstname' => 'Andrei',
                    'lastname' => 'Hajdukewycz',
                    'nickname' => 'Sancus',
                    'emailhidden' => 0,
                    'homepage' => 'http://www.worldofwarcraft.com',
                    'confirmationcode' => '',
                    'created' => '2006-09-28 08:57:24',
                    'modified' => '2006-09-28 08:57:24'
                    );
        $controller->Session->setReturnValue('read', $userdata, 'User');
    }

    /**
     * Log out
     */
    function logout(&$controller) {
        $controller->Session->setReturnvalue('read', null, 'User');
    }

    /**
     * Compares two arrays to see if they contain the same values.  Returns TRUE or FALSE.
     * useful for determining if a record or block of data was modified (perhaps by user input)
     * prior to setting a "date_last_updated" or skipping updating the db in the case of no change.
     *
     * From some random comment on php.net!
     *
     * @param array $a1
     * @param array $a2
     * @return boolean
     */
    function array_compare_recursive($a1, $a2)
    {
        if (!(is_array($a1) and (is_array($a2)))) return false;
        
        if (!count($a1) == count($a2)) {
            return false; // arrays don't have same number of entries
        }
        
        foreach ($a1 as $key => $val) {
            if (!array_key_exists($key, $a2)) {
                // uncomparable array keys don't match
                return false;
                
            } elseif (is_array($val) and is_array($a2[$key])) {
                // if both entries are arrays then compare recursive
                if (!$this->array_compare_recursive($val,$a2[$key])) return false;
                
            } elseif (!($val === $a2[$key])) {
                // compare entries must be of same type.
                return false;
            }
        }
        return true; // $a1 === $a2
    }

}

?>