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 2.0.0
44
 */
45
 
46
require_once 'PHPUnit/Framework.php';
47
 
48
require_once 'PHPUnit/Util/CodeCoverage.php';
49
require_once 'PHPUnit/Util/ErrorHandler.php';
50
require_once 'PHPUnit/Util/InvalidArgumentHelper.php';
51
require_once 'PHPUnit/Util/Printer.php';
52
require_once 'PHPUnit/Util/Test.php';
53
require_once 'PHPUnit/Util/Timer.php';
54
 
55
PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');
56
 
57
/**
58
 * A TestResult collects the results of executing a test case.
59
 *
60
 * @category   Testing
61
 * @package    PHPUnit
62
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
63
 * @copyright  2002-2010 Sebastian Bergmann <sb@sebastian-bergmann.de>
64
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
65
 * @version    Release: 3.4.15
66
 * @link       http://www.phpunit.de/
67
 * @since      Class available since Release 2.0.0
68
 */
69
class PHPUnit_Framework_TestResult implements Countable
70
{
71
    /**
72
     * @var boolean
73
     */
74
    protected static $xdebugLoaded = NULL;
75
 
76
    /**
77
     * @var boolean
78
     */
79
    protected static $useXdebug = NULL;
80
 
81
    /**
82
     * @var    array
83
     */
84
    protected $passed = array();
85
 
86
    /**
87
     * @var    array
88
     */
89
    protected $errors = array();
90
 
91
    /**
92
     * @var    array
93
     */
94
    protected $failures = array();
95
 
96
    /**
97
     * @var    array
98
     */
99
    protected $notImplemented = array();
100
 
101
    /**
102
     * @var    array
103
     */
104
    protected $skipped = array();
105
 
106
    /**
107
     * @var    array
108
     */
109
    protected $listeners = array();
110
 
111
    /**
112
     * @var    integer
113
     */
114
    protected $runTests = 0;
115
 
116
    /**
117
     * @var    float
118
     */
119
    protected $time = 0;
120
 
121
    /**
122
     * @var    PHPUnit_Framework_TestSuite
123
     */
124
    protected $topTestSuite = NULL;
125
 
126
    /**
127
     * Code Coverage information provided by Xdebug.
128
     *
129
     * @var    array
130
     */
131
    protected $codeCoverageInformation = array();
132
 
133
    /**
134
     * @var    boolean
135
     */
136
    protected $collectCodeCoverageInformation = FALSE;
137
 
138
    /**
139
     * @var    boolean
140
     */
141
    protected $collectRawCodeCoverageInformation = FALSE;
142
 
143
    /**
144
     * @var    boolean
145
     */
146
    protected $convertErrorsToExceptions = TRUE;
147
 
148
    /**
149
     * @var    boolean
150
     */
151
    protected $stop = FALSE;
152
 
153
    /**
154
     * @var    boolean
155
     */
156
    protected $stopOnFailure = FALSE;
157
 
158
    /**
159
     * @var    boolean
160
     */
161
    protected $lastTestFailed = FALSE;
162
 
163
    /**
164
     * Registers a TestListener.
165
     *
166
     * @param  PHPUnit_Framework_TestListener
167
     */
168
    public function addListener(PHPUnit_Framework_TestListener $listener)
169
    {
170
        $this->listeners[] = $listener;
171
    }
172
 
173
    /**
174
     * Unregisters a TestListener.
175
     *
176
     * @param  PHPUnit_Framework_TestListener $listener
177
     */
178
    public function removeListener(PHPUnit_Framework_TestListener $listener)
179
    {
180
        foreach ($this->listeners as $key => $_listener) {
181
            if ($listener === $_listener) {
182
                unset($this->listeners[$key]);
183
            }
184
        }
185
    }
186
 
187
    /**
188
     * Flushes all flushable TestListeners.
189
     *
190
     * @since  Method available since Release 3.0.0
191
     */
192
    public function flushListeners()
193
    {
194
        foreach ($this->listeners as $listener) {
195
            if ($listener instanceof PHPUnit_Util_Printer) {
196
                $listener->flush();
197
            }
198
        }
199
    }
200
 
201
    /**
202
     * Adds an error to the list of errors.
203
     *
204
     * @param  PHPUnit_Framework_Test $test
205
     * @param  Exception              $e
206
     * @param  float                  $time
207
     */
208
    public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
209
    {
210
        if ($e instanceof PHPUnit_Framework_IncompleteTest) {
211
            $this->notImplemented[] = new PHPUnit_Framework_TestFailure(
212
              $test, $e
213
            );
214
 
215
            $notifyMethod = 'addIncompleteTest';
216
        }
217
 
218
        else if ($e instanceof PHPUnit_Framework_SkippedTest) {
219
            $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e);
220
            $notifyMethod    = 'addSkippedTest';
221
        }
222
 
223
        else {
224
            $this->errors[] = new PHPUnit_Framework_TestFailure($test, $e);
225
            $notifyMethod   = 'addError';
226
 
227
            if ($this->stopOnFailure) {
228
                $this->stop();
229
            }
230
        }
231
 
232
        foreach ($this->listeners as $listener) {
233
            $listener->$notifyMethod($test, $e, $time);
234
        }
235
 
236
        $this->lastTestFailed = TRUE;
237
        $this->time          += $time;
238
    }
239
 
240
    /**
241
     * Adds a failure to the list of failures.
242
     * The passed in exception caused the failure.
243
     *
244
     * @param  PHPUnit_Framework_Test                 $test
245
     * @param  PHPUnit_Framework_AssertionFailedError $e
246
     * @param  float                                  $time
247
     */
248
    public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
249
    {
250
        if ($e instanceof PHPUnit_Framework_IncompleteTest) {
251
            $this->notImplemented[] = new PHPUnit_Framework_TestFailure(
252
              $test, $e
253
            );
254
 
255
            $notifyMethod = 'addIncompleteTest';
256
        }
257
 
258
        else if ($e instanceof PHPUnit_Framework_SkippedTest) {
259
            $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e);
260
            $notifyMethod    = 'addSkippedTest';
261
        }
262
 
263
        else {
264
            $this->failures[] = new PHPUnit_Framework_TestFailure($test, $e);
265
            $notifyMethod     = 'addFailure';
266
 
267
            if ($this->stopOnFailure) {
268
                $this->stop();
269
            }
270
        }
271
 
272
        foreach ($this->listeners as $listener) {
273
            $listener->$notifyMethod($test, $e, $time);
274
        }
275
 
276
        $this->lastTestFailed = TRUE;
277
        $this->time          += $time;
278
    }
279
 
280
    /**
281
     * Informs the result that a testsuite will be started.
282
     *
283
     * @param  PHPUnit_Framework_TestSuite $suite
284
     * @since  Method available since Release 2.2.0
285
     */
286
    public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
287
    {
288
        if ($this->topTestSuite === NULL) {
289
            $this->topTestSuite = $suite;
290
        }
291
 
292
        foreach ($this->listeners as $listener) {
293
            $listener->startTestSuite($suite);
294
        }
295
    }
296
 
297
    /**
298
     * Informs the result that a testsuite was completed.
299
     *
300
     * @param  PHPUnit_Framework_TestSuite $suite
301
     * @since  Method available since Release 2.2.0
302
     */
303
    public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
304
    {
305
        foreach ($this->listeners as $listener) {
306
            $listener->endTestSuite($suite);
307
        }
308
    }
309
 
310
    /**
311
     * Informs the result that a test will be started.
312
     *
313
     * @param  PHPUnit_Framework_Test $test
314
     */
315
    public function startTest(PHPUnit_Framework_Test $test)
316
    {
317
        $this->lastTestFailed = FALSE;
318
        $this->runTests      += count($test);
319
 
320
        foreach ($this->listeners as $listener) {
321
            $listener->startTest($test);
322
        }
323
    }
324
 
325
    /**
326
     * Informs the result that a test was completed.
327
     *
328
     * @param  PHPUnit_Framework_Test $test
329
     * @param  float                  $time
330
     */
331
    public function endTest(PHPUnit_Framework_Test $test, $time)
332
    {
333
        foreach ($this->listeners as $listener) {
334
            $listener->endTest($test, $time);
335
        }
336
 
337
        if (!$this->lastTestFailed && $test instanceof PHPUnit_Framework_TestCase) {
338
            $this->passed[get_class($test) . '::' . $test->getName()] = $test->getResult();
339
            $this->time += $time;
340
        }
341
    }
342
 
343
    /**
344
     * Returns TRUE if no incomplete test occured.
345
     *
346
     * @return boolean
347
     */
348
    public function allCompletlyImplemented()
349
    {
350
        return $this->notImplementedCount() == 0;
351
    }
352
 
353
    /**
354
     * Gets the number of incomplete tests.
355
     *
356
     * @return integer
357
     */
358
    public function notImplementedCount()
359
    {
360
        return count($this->notImplemented);
361
    }
362
 
363
    /**
364
     * Returns an Enumeration for the incomplete tests.
365
     *
366
     * @return array
367
     */
368
    public function notImplemented()
369
    {
370
        return $this->notImplemented;
371
    }
372
 
373
    /**
374
     * Returns TRUE if no test has been skipped.
375
     *
376
     * @return boolean
377
     * @since  Method available since Release 3.0.0
378
     */
379
    public function noneSkipped()
380
    {
381
        return $this->skippedCount() == 0;
382
    }
383
 
384
    /**
385
     * Gets the number of skipped tests.
386
     *
387
     * @return integer
388
     * @since  Method available since Release 3.0.0
389
     */
390
    public function skippedCount()
391
    {
392
        return count($this->skipped);
393
    }
394
 
395
    /**
396
     * Returns an Enumeration for the skipped tests.
397
     *
398
     * @return array
399
     * @since  Method available since Release 3.0.0
400
     */
401
    public function skipped()
402
    {
403
        return $this->skipped;
404
    }
405
 
406
    /**
407
     * Gets the number of detected errors.
408
     *
409
     * @return integer
410
     */
411
    public function errorCount()
412
    {
413
        return count($this->errors);
414
    }
415
 
416
    /**
417
     * Returns an Enumeration for the errors.
418
     *
419
     * @return array
420
     */
421
    public function errors()
422
    {
423
        return $this->errors;
424
    }
425
 
426
    /**
427
     * Gets the number of detected failures.
428
     *
429
     * @return integer
430
     */
431
    public function failureCount()
432
    {
433
        return count($this->failures);
434
    }
435
 
436
    /**
437
     * Returns an Enumeration for the failures.
438
     *
439
     * @return array
440
     */
441
    public function failures()
442
    {
443
        return $this->failures;
444
    }
445
 
446
    /**
447
     * Returns the names of the tests that have passed.
448
     *
449
     * @return array
450
     * @since  Method available since Release 3.4.0
451
     */
452
    public function passed()
453
    {
454
        return $this->passed;
455
    }
456
 
457
    /**
458
     * Returns the (top) test suite.
459
     *
460
     * @return PHPUnit_Framework_TestSuite
461
     * @since  Method available since Release 3.0.0
462
     */
463
    public function topTestSuite()
464
    {
465
        return $this->topTestSuite;
466
    }
467
 
468
    /**
469
     * Enables or disables the collection of Code Coverage information.
470
     *
471
     * @param  boolean $flag
472
     * @throws InvalidArgumentException
473
     * @since  Method available since Release 2.3.0
474
     */
475
    public function collectCodeCoverageInformation($flag)
476
    {
477
        if (is_bool($flag)) {
478
            $this->collectCodeCoverageInformation = $flag;
479
        } else {
480
            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
481
        }
482
    }
483
 
484
    /**
485
     * Enables or disables the collection of raw Code Coverage information.
486
     *
487
     * @param  boolean $flag
488
     * @throws InvalidArgumentException
489
     * @since  Method available since Release 3.4.0
490
     */
491
    public function collectRawCodeCoverageInformation($flag)
492
    {
493
        if (is_bool($flag)) {
494
            $this->collectRawCodeCoverageInformation = $flag;
495
 
496
            if ($flag === TRUE) {
497
                $this->collectCodeCoverageInformation = $flag;
498
            }
499
        } else {
500
            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
501
        }
502
    }
503
 
504
    /**
505
     * Returns whether code coverage information should be collected.
506
     *
507
     * @return boolean If code coverage should be collected
508
     * @since  Method available since Release 3.2.0
509
     */
510
    public function getCollectCodeCoverageInformation()
511
    {
512
        return $this->collectCodeCoverageInformation;
513
    }
514
 
515
    /**
516
     * Appends code coverage information to the test
517
     *
518
     * @param PHPUnit_Framework_Test $test
519
     * @param array                  $data
520
     * @since Method available since Release 3.2.0
521
     */
522
    public function appendCodeCoverageInformation(PHPUnit_Framework_Test $test, $data)
523
    {
524
        if ($this->collectRawCodeCoverageInformation) {
525
            $this->codeCoverageInformation[] = array(
526
              'test' => $test, 'data' => $data
527
            );
528
        } else {
529
            $deadCode       = array();
530
            $executableCode = array();
531
 
532
            foreach (array_keys($data) as $file) {
533
                if (PHPUnit_Util_Filter::isFiltered($file, FALSE)) {
534
                    unset($data[$file]);
535
                }
536
            }
537
 
538
            $newFilesToCollect = array_diff_key($data, PHPUnit_Util_Filter::getCoveredFiles());
539
 
540
            if (count($newFilesToCollect) > 0) {
541
                $deadCode = PHPUnit_Util_CodeCoverage::getDeadLines(
542
                  $newFilesToCollect
543
                );
544
 
545
                $executableCode = PHPUnit_Util_CodeCoverage::getExecutableLines(
546
                  $newFilesToCollect
547
                );
548
 
549
                foreach (array_keys($newFilesToCollect) as $file) {
550
                    PHPUnit_Util_Filter::addCoveredFile($file);
551
                }
552
 
553
                unset($newFilesToCollect);
554
            }
555
 
556
            if ($test instanceof PHPUnit_Framework_TestCase) {
557
                $linesToBeCovered = PHPUnit_Util_Test::getLinesToBeCovered(
558
                  get_class($test), $test->getName()
559
                );
560
 
561
                if (!empty($linesToBeCovered)) {
562
                    $data = array_intersect_key($data, $linesToBeCovered);
563
 
564
                    foreach (array_keys($data) as $file) {
565
                        $data[$file] = array_intersect_key(
566
                          $data[$file], array_flip($linesToBeCovered[$file])
567
                        );
568
                    }
569
                }
570
            }
571
 
572
            $executed = PHPUnit_Util_CodeCoverage::getExecutedLines($data);
573
            unset($data);
574
 
575
            $this->codeCoverageInformation[] = array(
576
              'test'       => $test,
577
              'files'      => $executed,
578
              'dead'       => $deadCode,
579
              'executable' => $executableCode,
580
            );
581
        }
582
    }
583
 
584
    /**
585
     * Returns the raw Code Coverage information.
586
     *
587
     * @return array
588
     * @since  Method available since Release 3.4.0
589
     */
590
    public function getRawCodeCoverageInformation()
591
    {
592
        return $this->codeCoverageInformation;
593
    }
594
 
595
    /**
596
     * Returns Code Coverage data per test case.
597
     *
598
     * Format of the result array:
599
     *
600
     * <code>
601
     * array(
602
     *   array(
603
     *     'test'  => PHPUnit_Framework_Test
604
     *     'files' => array(
605
     *       "/tested/code.php" => array(
606
     *         linenumber => flag
607
     *       )
608
     *     )
609
     *   )
610
     * )
611
     * </code>
612
     *
613
     * flag < 0: Line is executable but was not executed.
614
     * flag > 0: Line was executed.
615
     *
616
     * @param  boolean $filterTests
617
     * @return array
618
     */
619
    public function getCodeCoverageInformation($filterTests = TRUE)
620
    {
621
        return PHPUnit_Util_Filter::getFilteredCodeCoverage(
622
          $this->codeCoverageInformation, $filterTests
623
        );
624
    }
625
 
626
    /**
627
     * Returns unfiltered Code Coverage data per test case.
628
     * Returns data in the same form as getCodeCoverageInformation().
629
     *
630
     * @return array
631
     */
632
    public function getUncoveredWhitelistFiles()
633
    {
634
        list(, $missing) = PHPUnit_Util_Filter::getFileCodeCoverageDisposition(
635
          $this->codeCoverageInformation
636
        );
637
 
638
        return $missing;
639
    }
640
 
641
    /**
642
     * Runs a TestCase.
643
     *
644
     * @param  PHPUnit_Framework_Test $test
645
     */
646
    public function run(PHPUnit_Framework_Test $test)
647
    {
648
        PHPUnit_Framework_Assert::resetCount();
649
 
650
        $error   = FALSE;
651
        $failure = FALSE;
652
 
653
        $this->startTest($test);
654
 
655
        $errorHandlerSet = FALSE;
656
 
657
        if ($this->convertErrorsToExceptions) {
658
            $oldErrorHandler = set_error_handler(
659
              array('PHPUnit_Util_ErrorHandler', 'handleError'),
660
              E_ALL | E_STRICT
661
            );
662
 
663
            if ($oldErrorHandler === NULL) {
664
                $errorHandlerSet = TRUE;
665
            } else {
666
                restore_error_handler();
667
            }
668
        }
669
 
670
        if (self::$xdebugLoaded === NULL) {
671
            self::$xdebugLoaded = extension_loaded('xdebug');
672
            self::$useXdebug    = self::$xdebugLoaded;
673
        }
674
 
675
        $useXdebug = self::$useXdebug &&
676
                     $this->collectCodeCoverageInformation &&
677
                     !$test instanceof PHPUnit_Extensions_SeleniumTestCase;
678
 
679
        if ($useXdebug) {
680
            xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
681
        }
682
 
683
        PHPUnit_Util_Timer::start();
684
 
685
        try {
686
            $test->runBare();
687
        }
688
 
689
        catch (PHPUnit_Framework_AssertionFailedError $e) {
690
            $failure = TRUE;
691
        }
692
 
693
        catch (Exception $e) {
694
            $error = TRUE;
695
        }
696
 
697
        $time = PHPUnit_Util_Timer::stop();
698
 
699
        if ($useXdebug) {
700
            $codeCoverage = xdebug_get_code_coverage();
701
            xdebug_stop_code_coverage();
702
 
703
            if (!$test instanceof PHPUnit_Framework_Warning) {
704
                $this->appendCodeCoverageInformation(
705
                  $test, $codeCoverage
706
                );
707
            }
708
        }
709
 
710
        if ($errorHandlerSet === TRUE) {
711
            restore_error_handler();
712
        }
713
 
714
        $test->addToAssertionCount(PHPUnit_Framework_Assert::getCount());
715
 
716
        if ($error === TRUE) {
717
            $this->addError($test, $e, $time);
718
        }
719
 
720
        else if ($failure === TRUE) {
721
            $this->addFailure($test, $e, $time);
722
        }
723
 
724
        $this->endTest($test, $time);
725
    }
726
 
727
    /**
728
     * Gets the number of run tests.
729
     *
730
     * @return integer
731
     */
732
    public function count()
733
    {
734
        return $this->runTests;
735
    }
736
 
737
    /**
738
     * Checks whether the test run should stop.
739
     *
740
     * @return boolean
741
     */
742
    public function shouldStop()
743
    {
744
        return $this->stop;
745
    }
746
 
747
    /**
748
     * Marks that the test run should stop.
749
     *
750
     */
751
    public function stop()
752
    {
753
        $this->stop = TRUE;
754
    }
755
 
756
    /**
757
     * Enables or disables the error-to-exception conversion.
758
     *
759
     * @param  boolean $flag
760
     * @throws InvalidArgumentException
761
     * @since  Method available since Release 3.2.14
762
     */
763
    public function convertErrorsToExceptions($flag)
764
    {
765
        if (is_bool($flag)) {
766
            $this->convertErrorsToExceptions = $flag;
767
        } else {
768
            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
769
        }
770
    }
771
 
772
    /**
773
     * Returns the error-to-exception conversion setting.
774
     *
775
     * @return boolean
776
     * @since  Method available since Release 3.4.0
777
     */
778
    public function getConvertErrorsToExceptions()
779
    {
780
        return $this->convertErrorsToExceptions;
781
    }
782
 
783
    /**
784
     * Enables or disables the stopping when a failure or error occurs.
785
     *
786
     * @param  boolean $flag
787
     * @throws InvalidArgumentException
788
     * @since  Method available since Release 3.1.0
789
     */
790
    public function stopOnFailure($flag)
791
    {
792
        if (is_bool($flag)) {
793
            $this->stopOnFailure = $flag;
794
        } else {
795
            throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean');
796
        }
797
    }
798
 
799
    /**
800
     * Returns the time spent running the tests.
801
     *
802
     * @return float
803
     */
804
    public function time()
805
    {
806
        return $this->time;
807
    }
808
 
809
    /**
810
     * Returns whether the entire test was successful or not.
811
     *
812
     * @return boolean
813
     */
814
    public function wasSuccessful()
815
    {
816
        return empty($this->errors) && empty($this->failures);
817
    }
818
}
819
?>