Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * PHPUnit
4
 *
5
 * Copyright (c) 2002-2010, Sebastian Bergmann <sb@sebastian-bergmann.de>.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 *
12
 *   * Redistributions of source code must retain the above copyright
13
 *     notice, this list of conditions and the following disclaimer.
14
 *
15
 *   * Redistributions in binary form must reproduce the above copyright
16
 *     notice, this list of conditions and the following disclaimer in
17
 *     the documentation and/or other materials provided with the
18
 *     distribution.
19
 *
20
 *   * Neither the name of Sebastian Bergmann nor the names of his
21
 *     contributors may be used to endorse or promote products derived
22
 *     from this software without specific prior written permission.
23
 *
24
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
 * POSSIBILITY OF SUCH DAMAGE.
36
 *
37
 * @category   Testing
38
 * @package    PHPUnit
39
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
40
 * @copyright  2002-2010 Sebastian Bergmann <sb@sebastian-bergmann.de>
41
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
42
 * @link       http://www.phpunit.de/
43
 * @since      File available since Release 3.1.0
44
 */
45
 
46
require_once 'PHPUnit/Framework.php';
47
require_once 'PHPUnit/Runner/BaseTestRunner.php';
48
require_once 'PHPUnit/Util/Filter.php';
49
 
50
PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
51
 
52
/**
53
 * Writes test result and code coverage data to a database.
54
 *
55
 * @category   Testing
56
 * @package    PHPUnit
57
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
58
 * @copyright  2002-2010 Sebastian Bergmann <sb@sebastian-bergmann.de>
59
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
60
 * @version    Release: 3.4.15
61
 * @link       http://www.phpunit.de/
62
 * @since      Class available since Release 3.1.0
63
 */
64
class PHPUnit_Util_Log_Database implements PHPUnit_Framework_TestListener
65
{
66
    /**
67
     * @var    PHPUnit_Util_Log_Database
68
     */
69
    protected static $instance = NULL;
70
 
71
    /**
72
     * @var    integer
73
     */
74
    protected $currentTestId;
75
 
76
    /**
77
     * @var    integer
78
     */
79
    protected $runId;
80
 
81
    /**
82
     * @var    integer[]
83
     */
84
    protected $testSuites = array();
85
 
86
    /**
87
     * @var    boolean
88
     */
89
    protected $currentTestSuccess = TRUE;
90
 
91
    /**
92
     * @var    PDO
93
     */
94
    protected $dbh;
95
 
96
    /**
97
     * Constructor.
98
     *
99
     * @param  PDO     $dbh
100
     * @param  integer $revision
101
     * @param  string  $information
102
     * @throws PDOException
103
     * @throws RuntimeException
104
     */
105
    protected function __construct(PDO $dbh, $revision, $information = '')
106
    {
107
        $this->dbh = $dbh;
108
 
109
        $stmt = $this->dbh->prepare(
110
          'INSERT INTO run
111
                       (timestamp, revision, information)
112
                 VALUES(:timestamp, :revision, :information);'
113
        );
114
 
115
        $timestamp = time();
116
 
117
        $stmt->bindParam(':timestamp', $timestamp, PDO::PARAM_INT);
118
        $stmt->bindParam(':revision', $revision, PDO::PARAM_INT);
119
        $stmt->bindParam(':information', $information, PDO::PARAM_STR);
120
        $stmt->execute();
121
 
122
        $this->runId = $this->dbh->lastInsertId();
123
    }
124
 
125
    /**
126
     * @param  PDO     $dbh
127
     * @param  integer $revision
128
     * @param  string  $information
129
     * @return PHPUnit_Util_Log_Database
130
     * @throws InvalidArgumentException
131
     * @throws PDOException
132
     * @throws RuntimeException
133
     */
134
    public static function getInstance(PDO $dbh = NULL, $revision = '', $information = '')
135
    {
136
        if ($dbh === NULL) {
137
            if (self::$instance != NULL) {
138
                return self::$instance;
139
            } else {
140
                return FALSE;
141
            }
142
        }
143
 
144
        if (self::$instance != NULL) {
145
            throw new RuntimeException;
146
        }
147
 
148
        if (empty($revision)) {
149
            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'non-empty string');
150
        }
151
 
152
        self::$instance = new PHPUnit_Util_Log_Database(
153
          $dbh, $revision, $information
154
        );
155
 
156
        return self::$instance;
157
    }
158
 
159
    /**
160
     * Returns the ID of the current test.
161
     *
162
     * @return integer
163
     */
164
    public function getCurrentTestId()
165
    {
166
        return $this->currentTestId;
167
    }
168
 
169
    /**
170
     * Returns the ID of this test run.
171
     *
172
     * @return integer
173
     */
174
    public function getRunId()
175
    {
176
        return $this->runId;
177
    }
178
 
179
    /**
180
     * An error occurred.
181
     *
182
     * @param  PHPUnit_Framework_Test $test
183
     * @param  Exception              $e
184
     * @param  float                  $time
185
     */
186
    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
187
    {
188
        $message = PHPUnit_Framework_TestFailure::exceptionToString($e) . "\n" .
189
                   PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE);
190
 
191
        $this->storeResult(
192
          PHPUnit_Runner_BaseTestRunner::STATUS_ERROR,
193
          $time,
194
          $message
195
        );
196
 
197
        $this->updateParents(
198
          $time, PHPUnit_Runner_BaseTestRunner::STATUS_ERROR
199
        );
200
 
201
        $this->currentTestSuccess = FALSE;
202
    }
203
 
204
    /**
205
     * A failure occurred.
206
     *
207
     * @param  PHPUnit_Framework_Test                 $test
208
     * @param  PHPUnit_Framework_AssertionFailedError $e
209
     * @param  float                                  $time
210
     */
211
    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
212
    {
213
        $message = PHPUnit_Framework_TestFailure::exceptionToString($e) . "\n" .
214
                   PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE);
215
 
216
        $this->storeResult(
217
          PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE,
218
          $time,
219
          $message
220
        );
221
 
222
        $this->updateParents(
223
          $time, PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE
224
        );
225
 
226
        $this->currentTestSuccess = FALSE;
227
    }
228
 
229
    /**
230
     * Incomplete test.
231
     *
232
     * @param  PHPUnit_Framework_Test $test
233
     * @param  Exception              $e
234
     * @param  float                  $time
235
     */
236
    public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
237
    {
238
        $message = PHPUnit_Framework_TestFailure::exceptionToString($e) . "\n" .
239
                   PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE);
240
 
241
        $this->storeResult(
242
          PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE,
243
          $time,
244
          $message
245
        );
246
 
247
        $this->currentTestSuccess = FALSE;
248
    }
249
 
250
    /**
251
     * Skipped test.
252
     *
253
     * @param  PHPUnit_Framework_Test $test
254
     * @param  Exception              $e
255
     * @param  float                  $time
256
     */
257
    public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
258
    {
259
        $message = PHPUnit_Framework_TestFailure::exceptionToString($e) . "\n" .
260
                   PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE);
261
 
262
        $this->storeResult(
263
          PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED,
264
          $time,
265
          $message
266
        );
267
 
268
        $this->currentTestSuccess = FALSE;
269
    }
270
 
271
    /**
272
     * A test suite started.
273
     *
274
     * @param  PHPUnit_Framework_TestSuite $suite
275
     */
276
    public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
277
    {
278
        if (empty($this->testSuites)) {
279
            $testSuiteId = $this->insertRootNode($suite->getName());
280
        } else {
281
            $testSuiteId = $this->insertNode($suite);
282
        }
283
 
284
        $this->testSuites[] = array(
285
          'id'     => $testSuiteId,
286
          'result' => PHPUnit_Runner_BaseTestRunner::STATUS_PASSED
287
        );
288
    }
289
 
290
    /**
291
     * A test suite ended.
292
     *
293
     * @param  PHPUnit_Framework_TestSuite $suite
294
     */
295
    public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
296
    {
297
        array_pop($this->testSuites);
298
 
299
        if (empty($this->testSuites)) {
300
            $stmt = $this->dbh->prepare(
301
              'UPDATE run
302
                  SET completed = 1
303
                WHERE run_id = :runId;'
304
            );
305
 
306
            $stmt->bindParam(':runId', $this->runId, PDO::PARAM_INT);
307
            $stmt->execute();
308
        }
309
    }
310
 
311
    /**
312
     * A test started.
313
     *
314
     * @param  PHPUnit_Framework_Test $test
315
     */
316
    public function startTest(PHPUnit_Framework_Test $test)
317
    {
318
        $this->insertNode($test);
319
        $this->currentTestSuccess = TRUE;
320
    }
321
 
322
    /**
323
     * A test ended.
324
     *
325
     * @param  PHPUnit_Framework_Test $test
326
     * @param  float                  $time
327
     */
328
    public function endTest(PHPUnit_Framework_Test $test, $time)
329
    {
330
        if ($this->currentTestSuccess) {
331
            $this->storeResult(
332
              PHPUnit_Runner_BaseTestRunner::STATUS_PASSED, $time
333
            );
334
 
335
            $this->updateParents($time);
336
        }
337
    }
338
 
339
    /**
340
     * Inserts the root node into the tree.
341
     *
342
     * @param  string $name
343
     * @return integer
344
     * @throws PDOException
345
     */
346
    protected function insertRootNode($name)
347
    {
348
        $this->dbh->beginTransaction();
349
 
350
        $stmt = $this->dbh->prepare(
351
          'INSERT INTO test
352
                       (run_id, test_name, node_left, node_right, node_is_leaf,
353
                        node_parent, node_depth)
354
                 VALUES(:runId, :testName, 1, 2, 0, 0, 0);'
355
        );
356
 
357
        $stmt->bindParam(':runId', $this->runId, PDO::PARAM_INT);
358
        $stmt->bindParam(':testName', $name, PDO::PARAM_STR);
359
        $stmt->execute();
360
 
361
        $rootId = $this->dbh->lastInsertId();
362
 
363
        $stmt = $this->dbh->prepare(
364
          'UPDATE test
365
              SET node_root = :root
366
            WHERE test_id = :testId;'
367
        );
368
 
369
        $stmt->bindParam(':root', $rootId, PDO::PARAM_INT);
370
        $stmt->bindParam(':testId', $rootId, PDO::PARAM_INT);
371
        $stmt->execute();
372
 
373
        $this->dbh->commit();
374
 
375
        return $rootId;
376
    }
377
 
378
    /**
379
     * Inserts a node into the tree.
380
     *
381
     * @param  PHPUnit_Framework_Test $test
382
     * @throws PDOException
383
     */
384
    protected function insertNode(PHPUnit_Framework_Test $test)
385
    {
386
        $isLeaf = (int)!$test instanceof PHPUnit_Framework_TestSuite;
387
 
388
        $this->dbh->beginTransaction();
389
 
390
        $stmt = $this->dbh->prepare(
391
          'SELECT node_right
392
             FROM test
393
            WHERE test_id = :testId;'
394
        );
395
 
396
        $stmt->bindParam(':testId', $this->testSuites[count($this->testSuites)-1]['id'], PDO::PARAM_INT);
397
        $stmt->execute();
398
 
399
        $right = (int)$stmt->fetchColumn();
400
        unset($stmt);
401
 
402
        $stmt = $this->dbh->prepare(
403
          'UPDATE test
404
              SET node_left = node_left + 2
405
            WHERE node_root = :root
406
              AND node_left > :left;'
407
        );
408
 
409
        $stmt->bindParam(':root', $this->testSuites[0]['id'], PDO::PARAM_INT);
410
        $stmt->bindParam(':left', $right, PDO::PARAM_INT);
411
        $stmt->execute();
412
 
413
        $stmt = $this->dbh->prepare(
414
          'UPDATE test
415
              SET node_right  = node_right + 2
416
            WHERE node_root   = :root
417
              AND node_right >= :right;'
418
        );
419
 
420
        $stmt->bindParam(':root', $this->testSuites[0]['id'], PDO::PARAM_INT);
421
        $stmt->bindParam(':right', $right, PDO::PARAM_INT);
422
        $stmt->execute();
423
 
424
        $testName = $test->getName();
425
        $left     = $right;
426
        $right    = $right + 1;
427
 
428
        $stmt = $this->dbh->prepare(
429
          'INSERT INTO test
430
                       (run_id, test_name, test_result, test_message,
431
                        test_execution_time, node_root, node_parent, node_left,
432
                        node_right, node_depth, node_is_leaf)
433
                 VALUES(:runId, :testName, 0, "", 0, :root, :parent, :left, :right, :depth,
434
                        :isLeaf);'
435
        );
436
 
437
        $currentTestDepth = count($this->testSuites);
438
 
439
        $stmt->bindParam(':runId', $this->runId, PDO::PARAM_INT);
440
        $stmt->bindParam(':testName', $testName, PDO::PARAM_STR);
441
        $stmt->bindParam(':root', $this->testSuites[0]['id'], PDO::PARAM_INT);
442
        $stmt->bindParam(':parent', $this->testSuites[(count($this->testSuites)-1)]['id'], PDO::PARAM_INT);
443
        $stmt->bindParam(':left', $left, PDO::PARAM_INT);
444
        $stmt->bindParam(':right', $right, PDO::PARAM_INT);
445
        $stmt->bindPAram(':depth', $currentTestDepth, PDO::PARAM_INT);
446
        $stmt->bindParam(':isLeaf', $isLeaf, PDO::PARAM_INT);
447
        $stmt->execute();
448
 
449
        $this->currentTestId = $this->dbh->lastInsertId();
450
        $this->dbh->commit();
451
 
452
        if (!$test instanceof PHPUnit_Framework_TestSuite) {
453
            $test->__db_id = $this->currentTestId;
454
        }
455
 
456
        return $this->currentTestId;
457
    }
458
 
459
    /**
460
     * Stores a test result.
461
     *
462
     * @param  integer $result
463
     * @param  float   $time
464
     * @param  string  $message
465
     * @throws PDOException
466
     */
467
    protected function storeResult($result = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED, $time = 0, $message = '')
468
    {
469
        $stmt = $this->dbh->prepare(
470
          'UPDATE test
471
              SET test_result         = :result,
472
                  test_message        = :message,
473
                  test_execution_time = :executionTime
474
            WHERE test_id             = :testId;'
475
        );
476
 
477
        $stmt->bindParam(':result', $result, PDO::PARAM_INT);
478
        $stmt->bindParam(':message', $message, PDO::PARAM_STR);
479
        $stmt->bindParam(':executionTime', $time);
480
        $stmt->bindParam(':testId', $this->currentTestId, PDO::PARAM_INT);
481
        $stmt->execute();
482
    }
483
 
484
    /**
485
     * @param  float   $time
486
     * @param  integer $result
487
     * @throws PDOException
488
     */
489
    protected function updateParents($time, $result = NULL)
490
    {
491
        $stmtUpdateResultAndTime = $this->dbh->prepare(
492
          'UPDATE test
493
              SET test_result         = :result,
494
                  test_execution_time = test_execution_time + :time
495
            WHERE test_id             = :testSuiteId;'
496
        );
497
 
498
        $stmtUpdateTime = $this->dbh->prepare(
499
          'UPDATE test
500
              SET test_execution_time = test_execution_time + :time
501
            WHERE test_id             = :testSuiteId;'
502
        );
503
 
504
        foreach ($this->testSuites as &$testSuite) {
505
            if ($result > $testSuite['result']) {
506
                $stmtUpdateResultAndTime->bindParam(':result', $result, PDO::PARAM_INT);
507
                $stmtUpdateResultAndTime->bindParam(':testSuiteId', $testSuite['id'], PDO::PARAM_INT);
508
                $stmtUpdateResultAndTime->bindParam(':time', $time);
509
                $stmtUpdateResultAndTime->execute();
510
 
511
                $testSuite['result'] = $result;
512
            } else {
513
                $stmtUpdateTime->bindParam(':testSuiteId', $testSuite['id'], PDO::PARAM_INT);
514
                $stmtUpdateTime->bindParam(':time', $time);
515
                $stmtUpdateTime->execute();
516
            }
517
        }
518
    }
519
}
520
?>