Completed
Pull Request — develop (#720)
by Imants
03:58
created

Controller_Tester::runTests()   F

Complexity

Conditions 27
Paths 2448

Size

Total Lines 146
Code Lines 92

Duplication

Lines 36
Ratio 24.66 %

Importance

Changes 4
Bugs 2 Features 0
Metric Value
cc 27
c 4
b 2
f 0
dl 36
loc 146
rs 2
eloc 92
nc 2448
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Tester page is a basic implementation of a testing environment for Agile Toolkit.
4
 * See Documentation for testing.
5
 */
6
class Controller_Tester extends Page
7
{
8
    /** @var array */
9
    public $variances = array();
10
11
    /** @var mixed */
12
    public $input;
13
    
14
    /** @var array|string */
15
    public $responses = array();
16
17
    /** @var bool */
18
    public $auto_test = true;
19
20
    /** @var Grid $grid */
21
    public $grid;
22
23
    /** @var Form $form */
24
    public $form;
25
26
    /** @var int */
27
    public $cnt;
28
29
    /** Redefine this to the value generated by a test */
30
    public $proper_responses = null;
31
32 View Code Duplication
    public function setVariance($arr)
33
    {
34
        $this->variances = $arr;
35
        if (isset($this->grid)) {
36
            foreach ($arr as $key => $item) {
37
                if (is_numeric($key)) {
38
                    $key = $item;
39
                }
40
                $this->grid->addColumn('html', $key.'_inf', $key.' info');
41
                $this->grid->addColumn('html,wrap', $key.'_res', $key.' result');
42
            }
43
        }
44
    }
45
46
    public function init()
47
    {
48
        parent::init();
49
50
        if (!$this->auto_test) {
51
            $this->setVariance(array('Test'));
52
53
            return;    // used for multi-page testing
54
        }
55
        //$this->grid=$this->add('Grid');
56
        $this->grid->addColumn('template', 'name')
0 ignored issues
show
Bug introduced by
The method setTemplate does only exist in Grid, but not in Controller_Grid_Format.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
57
            ->setTemplate('<a href="'.$this->app->url(null, array('testonly' => '')).'<?$name?>"><?$name?></a>');
58
59
        $this->setVariance(array('Test'));
60
61
        //$this->setVariance(array('GiTemplate','SMlite'));
62
63
        //$this->runTests();
64
    }
65
66
    public function skipTests($msg = null)
67
    {
68
        throw $this->exception($msg, 'SkipTests');
69
    }
70
71
    public function ticker()
72
    {
73
        ++$this->cnt;
74
    }
75
76 View Code Duplication
    public function executeTest($test_obj, $test_func, $input)
77
    {
78
        if ($input === null) {
79
            $input = array();
80
        }
81
82
        return call_user_func_array(array($test_obj, $test_func), $input);
83
    }
84
85 View Code Duplication
    public function silentTest($test_obj = null)
86
    {
87
        if (!$test_obj) {
88
            $test_obj = $this;
89
        }
90
91
        $total = $success = $fail = $exception = 0;
92
        $speed = $memory = 0;
93
94
        $tested = array();
95
        $failures = array();
96
        foreach (get_class_methods($test_obj) as $method) {
97
            if (strpos($method, 'test_') === 0) {
98
                $m = substr($method, 5);
99
            } elseif (strpos($method, 'prepare_') === 0) {
100
                $m = substr($method, 8);
101
            } else {
102
                continue;
103
            }
104
            if ($tested[$m]) {
105
                continue;
106
            }
107
            $tested[$m] = true;
108
109
            foreach ($this->variances as $key => $vari) {
110
                if (is_numeric($key)) {
111
                    $key = $vari;
112
                }
113
114
                // Input is a result of preparation function
115
                try {
116
                    if (method_exists($test_obj, 'prepare_'.$m)) {
117
                        $input = $test_obj->{'prepare_'.$m}($vari, $method);
118
                    } else {
119
                        if (($test_obj instanceof AbstractObject && $test_obj->hasMethod('prepare'))
120
                            || method_exists($test_obj, 'prepare')
121
                        ) {
122
                            $input = $test_obj->prepare($vari, $method);
123
                        } else {
124
                            $input = null;
125
                        }
126
                    }
127
                } catch (Exception $e) {
128
                    if ($e instanceof Exception_SkipTests) {
129
                        return array(
130
                            'skipped' => $e->getMessage(),
131
                        );
132
                    }
133
                    throw $e;
134
                }
135
136
                $this->input = $input;
137
138
                $test_func = method_exists($test_obj, 'test_'.$m) ?
139
                    'test_'.$m : 'test';
140
141
                ++$total;
142
143
                $me = memory_get_peak_usage();
144
                $ms = microtime(true);
145
146
                $this->cnt = 0;
147
                declare (ticks = 1);
148
                register_tick_function(array($this, 'ticker'));
149
150
                try {
151
                    $result = $this->executeTest($test_obj, $test_func, $input);
152
                    $ms = microtime(true) - $ms;
153
                    $me = ($mend = memory_get_peak_usage()) - $me;
154
155
                    $result = $this->formatResult($row, $key, $result);
156
157
                    $k = $key.'_'.$m;
158
                    if ($this->proper_responses[$k] == $result && isset($this->proper_responses[$k])) {
159
                        ++$success;
160
                    } else {
161
                        $failures[] = $method;
162
                        ++$fail;
163
                    }
164
                } catch (Exception $e) {
165
                    if ($e instanceof Exception_SkipTests) {
166
                        return array(
167
                            'skipped' => $e->getMessage(),
168
                        );
169
                    }
170
171
                    ++$exception;
172
173
                    //$ms=microtime(true)-$ms;
174
                    $me = ($mend = memory_get_peak_usage()) - $me;
175
                }
176
177
                unregister_tick_function(array($this, 'ticker'));
178
179
                $speed += $this->cnt * 1;
180
                $memory += $me;
181
            }
182
        }
183
184
        return array(
185
            'total' => $total,
186
            'failures' => $failures,
187
            'success' => $success,
188
            'exception' => $exception,
189
            'fail' => $fail,
190
            'speed' => $speed,
191
            'memory' => $memory,
192
            );
193
    }
194
195
    public function runTests($test_obj = null)
196
    {
197
        if (!$test_obj) {
198
            $test_obj = $this;
199
        } else {
200
            $this->proper_responses = @$test_obj->proper_responses;
201
202
            if ($test_obj instanceof AbstractObject) {
203
                $this->add($test_obj);
204
            }
205
        }
206
207
        $tested = array();
208
        $data = array();
209
        foreach (get_class_methods($test_obj) as $method) {
210
            $m = '';
211
            if (strpos($method, 'test_') === 0) {
212
                $m = substr($method, 5);
213
            } elseif (strpos($method, 'prepare_') === 0) {
214
                $m = substr($method, 8);
215
            } else {
216
                continue;
217
            }
218
219
            if (isset($_GET['testonly']) && 'test_'.$_GET['testonly'] != $method) {
220
                continue;
221
            }
222
223
            // Do not retest same function even if it has both prepare and test
224
            if ($tested[$m]) {
225
                continue;
226
            }
227
            $tested[$m] = true;
228
229
            // Row contains test result data
230
            $row = array('name' => $m, 'id' => $m);
231
232
            foreach ($this->variances as $key => $vari) {
233
                if (is_numeric($key)) {
234
                    $key = $vari;
235
                }
236
237
                try {
238
                    // Input is a result of preparation function
239
                    if (method_exists($test_obj, 'prepare_'.$m)) {
240
                        $input = $test_obj->{'prepare_'.$m}($vari, $method);
241
                    } else {
242
                        if (($test_obj instanceof AbstractObject && $test_obj->hasMethod('prepare'))
243
                            || method_exists($test_obj, 'prepare')
244
                        ) {
245
                            $input = $test_obj->prepare($vari, $method);
246
                        } else {
247
                            $input = null;
248
                        }
249
                    }
250
                } catch (Exception $e) {
251 View Code Duplication
                    if ($e instanceof Exception_SkipTests) {
252
                        $this->grid->destroy();
253
                        
254
                        /** @type View_Error $v */
255
                        $v = $this->add('View_Error');
256
                        $v->set('Skipping all tests: '.$e->getMessage());
257
258
                        return;
259
                    }
260
                    throw $e;
261
                }
262
263
                $this->input = $input;
264
265
                $test_func = method_exists($test_obj, 'test_'.$m) ?
266
                    'test_'.$m : 'test';
267
268
                // Test speed
269
                $me = memory_get_peak_usage();
270
                $ms = microtime(true);
271
                $this->cnt = 0;
272
                declare (ticks = 1);
273
                register_tick_function(array($this, 'ticker'));
274
                try {
275
                    //$result=$test_obj->$test_func($input[0],$input[1],$input[2]);
276
                    $result = $this->executeTest($test_obj, $test_func, $input);
277
                } catch (Exception $e) {
278 View Code Duplication
                    if ($e instanceof Exception_SkipTests) {
279
                        $this->grid->destroy();
280
281
                        /** @type View_Error $v */
282
                        $v = $this->add('View_Error');
283
                        $v->set('Skipping all tests: '.$e->getMessage());
284
                    }
285
286 View Code Duplication
                    if ($_GET['tester_details'] == $row['name'] && $_GET['vari'] == $vari) {
287
                        throw $e;
288
                    }
289
290
                    $result = 'Exception: '.($e instanceof BaseException ? $e->getText() : $e->getMessage());
291
292
                    /** @type P $ll */
293
                    $ll = $this->add('P', $row['name']);
294
                    
295
                    /** @type View $v */
296
                    $v = $ll->add('View');
297
                    $v->setElement('a')
298
                        ->setAttr('href', '#')
299
                        ->set('More details')
300
                        ->js('click')->univ()->frameURL(
301
                            'Exception Details for test '.$row['name'],
302
                            $this->app->url(null, array('tester_details' => $row['name'], 'vari' => $vari))
303
                        );
304
305
                    $result .= $ll->getHTML();
306
                }
307
                $ms = microtime(true) - $ms;
308
                $me = ($mend = memory_get_peak_usage()) - $me;
309
                unregister_tick_function(array($this, 'ticker'));
310
311
                $row[$key.'_inf'] = 'Ticks: '.($this->cnt * 1).'<br/>Memory: '.$me;
312
313
                $result = $this->formatResult($row, $key, $result);
314
315
                $k = $key.'_'.$row['name'];
316 View Code Duplication
                if ($this->proper_responses[$k] == $result && isset($this->proper_responses[$k])) {
317
                    $row[$key.'_res'] = '<font color="green">PASS</font><br/>'.htmlspecialchars($result);
318
                } elseif (isset($this->proper_responses[$k])) {
319
                    $row[$key.'_res'] = '<font color="red">'.htmlspecialchars($result).'</font><br/>'.
320
                        var_export($this->proper_responses[$k], true);
321
                }
322
323
                $this->responses[] = '"'.$k.'"'.'=>'.var_export($result, true);
324
            }
325
326
            $data[] = $row;
327
        }
328
        $this->grid->setSource($data);
329 View Code Duplication
        if (!$_GET['testonly']) {
330
            $f = $this->form;
331
            $ff = $f->addField('Text', 'responses');
332
            $this->responses =
333
                '    public $proper_responses=array(
334
                '.implode(',
335
                ', $this->responses).'
336
                );';
337
            $ff->set($this->responses);
338
            $ff->js('click')->select();
339
        }
340
    }
341
342
    public function formatResult(&$row, $key, $result)
343
    {
344
        $row[$key.'_res'] = $result;
345
346
        return (string) $result;
347
    }
348
    
349
    public function expect($value, $expectation)
350
    {
351
        return $value == $expectation ? 'OK' : 'ERR';
352
    }
353
354 View Code Duplication
    public function _prepare($t, $str)
355
    {
356
        $result = '';
357
358
        for ($i = 0; $i < 100; ++$i) {
359
            $result .= $str;
360
        }
361
362
        return array($this->add($t), $result);
363
    }
364
}
365