17
17
* -o : Display output.
18
18
* -i : Display method timers.
19
19
* -u {unitname} : Run only the specified units.
20
+ * -v : Do code coverage.
20
21
*/
21
22
22
23
if (defined ('STDIN ' ) && function_exists ( 'getopt ' ) ) {
23
- $ shortopts = 'u::d::c::t::r::oi ' ;
24
+ $ shortopts = 'u::d::c::t::r::o::vi ' ;
24
25
$ options = getopt ($ shortopts );
25
26
}
26
27
if (!isset ($ options ) || !$ options ) {
27
28
$ options = array ();
28
29
}
29
30
global $ querystring_options ;
30
31
if (!isset ($ querystring_options )) {
31
- $ querystring_options = array_intersect_key ($ _GET , array ('o ' =>1 ,'t ' =>'' ,'c ' =>'' ,'d ' =>'' ,'u ' =>'' ,'i ' =>1 ));
32
+ $ querystring_options = array_intersect_key ($ _GET , array ('o ' =>1 ,'t ' =>'' ,'c ' =>'' ,'d ' =>'' ,'u ' =>'' ,'i ' =>1 , ' v ' => '' ));
32
33
$ options = array_merge ($ options , $ querystring_options );
33
34
}
34
35
@@ -131,6 +132,17 @@ public function assert_identical($value1, $value2, $message = 'Assertion failed'
131
132
}
132
133
}
133
134
135
+ public function assert_not_identical ($ value1 , $ value2 , $ message = 'Assertion failed ' )
136
+ {
137
+ if ($ value1 === $ value2 ) {
138
+ $ this ->messages [] = array (self ::FAIL , $ message , debug_backtrace ());
139
+ $ this ->fail_count ++;
140
+ }
141
+ else {
142
+ $ this ->pass_count ++;
143
+ }
144
+ }
145
+
134
146
public function assert_exception ($ exception = '' , $ message = 'Expected exception ' )
135
147
{
136
148
$ this ->asserted_exception = array ($ exception , $ message );
@@ -250,6 +262,10 @@ public function run()
250
262
$ this ->module_setup ();
251
263
}
252
264
265
+ if (isset ($ options ['v ' ])) {
266
+ xdebug_start_code_coverage ( XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE );
267
+ }
268
+
253
269
// If specific tests are specified to run within this unit, get that list
254
270
if (isset ($ options ['t ' ])) {
255
271
$ options ['t ' ] = explode (', ' , $ options ['t ' ]);
@@ -375,7 +391,13 @@ public function run()
375
391
376
392
$ this ->result ->case_count ++;
377
393
}
378
-
394
+
395
+ if (isset ($ options ['v ' ])) {
396
+ $ this ->result ->record_code_coverage (xdebug_get_code_coverage ());
397
+
398
+ xdebug_stop_code_coverage ();
399
+ }
400
+
379
401
if (method_exists ($ this , 'module_teardown ' )) {
380
402
$ this ->module_teardown ();
381
403
}
@@ -515,6 +537,8 @@ class TestResult
515
537
public $ file = '' ;
516
538
public $ summaries = array ();
517
539
private $ options = array ();
540
+ private $ type ;
541
+ public $ code_coverage = array ();
518
542
519
543
function __construct ($ test_name , $ file = null )
520
544
{
@@ -562,6 +586,21 @@ function summary($values)
562
586
{
563
587
$ this ->summaries = array_merge ($ this ->summaries , $ values );
564
588
}
589
+
590
+ function record_code_coverage ($ coverage )
591
+ {
592
+ foreach ($ coverage as $ filename => $ lines ) {
593
+ if (!isset ($ this ->code_coverage [$ filename ])) {
594
+ $ this ->code_coverage [$ filename ] = array ();
595
+ }
596
+ foreach ($ lines as $ line_number => $ result ) {
597
+ if (isset ($ this ->code_coverage [$ filename ][$ line_number ])) {
598
+ $ result = max ($ this ->code_coverage [$ filename ][$ line_number ], $ result );
599
+ }
600
+ $ this ->code_coverage [$ filename ][$ line_number ] = $ result ;
601
+ }
602
+ }
603
+ }
565
604
}
566
605
567
606
@@ -689,6 +728,71 @@ function out_html()
689
728
$ output .= "<div class= \"test complete \"><p> {$ summary ['case_count ' ]}/ {$ summary ['total_case_count ' ]} tests complete. {$ summary ['fail_count ' ]} failed assertions. {$ summary ['pass_count ' ]} passed assertions. {$ summary ['exception_count ' ]} exceptions. {$ summary ['incomplete_count ' ]} incomplete tests. {$ summary ['skipped_count ' ]} skipped tests.</p></div> " ;
690
729
}
691
730
731
+ if ( count ($ test ->code_coverage ) ) {
732
+ ksort ($ test ->code_coverage );
733
+ $ output .= '<h1>Code Coverage</h1> ' ;
734
+
735
+ // @todo what about @covers comments?
736
+ // @todo and @codeCoverageIgnore, @codeCoverageIgnoreStart, and @codeCoverageIgnoreEnd?
737
+ $ file_id = 0 ;
738
+ foreach ( $ test ->code_coverage as $ file => $ coverage ) {
739
+
740
+ $ file_id ++;
741
+ $ output .= '<h4> ' . $ file . '</h4> ' ;
742
+
743
+ if (!file_exists ($ file )) {
744
+ $ output .= '<div>File could not be opened to display coverage.</div> ' ;
745
+ continue ;
746
+ }
747
+ $ lines = file ( $ file );
748
+
749
+ $ output_file = '' ;
750
+ $ executed = 0 ;
751
+ $ executable = 0 ;
752
+ $ inaccessible = 0 ;
753
+
754
+ $ output_file .= '<table class="coverage" id="coverage_ ' . $ file_id . '"> ' ;
755
+ for ($ i = 0 ; $ i < count ($ lines ); $ i ++) {
756
+ $ line_number = $ i + 1 ;
757
+ $ line = $ lines [$ i ];
758
+ if ( isset ($ coverage [$ line_number ]) ) {
759
+ $ result = $ coverage [$ line_number ];
760
+ if ( $ result == -2 && (trim ($ line ) != '} ' ) ) { // This code is inaccessible
761
+ $ class = 'inaccessible ' ;
762
+ $ inaccessible ++;
763
+ $ executable ++;
764
+ }
765
+ else if ( $ result > 0 ) { // This code executed
766
+ $ class = 'executed ' ;
767
+ $ executed ++;
768
+ $ executable ++;
769
+ }
770
+ else if ( $ result == -1 ) { // This code did not execute
771
+ $ class = 'unexecuted ' ;
772
+ $ executable ++;
773
+ }
774
+ else {
775
+ $ class = 'whitespace ' ;
776
+ }
777
+ }
778
+ else {
779
+ $ class = 'unknown ' ;
780
+ }
781
+ $ output_file .= "<tr><td class= \"line_number \"> {$ line_number }</td><td class= \"codeline {$ class }\"> " . htmlentities ( $ line ) . "</td></tr> " ;
782
+ }
783
+ $ output_file .= '</table> ' ;
784
+
785
+ $ output .= '<details><summary> ' . $ executed . ' executed ' ;
786
+ if ($ inaccessible > 0 ) {
787
+ $ output .= ', ' . $ inaccessible . ' inaccessible ' ;
788
+ }
789
+ $ pct = round ($ executed * 100 / $ executable );
790
+ $ output .= ' out of ' . $ executable . ' lines -- ' . $ pct . '%</summary> ' ;
791
+ $ output .= $ output_file ;
792
+ $ output .= '</details> ' ;
793
+ }
794
+ }
795
+
692
796
$ output .= '<footer><h3>Results</h3> ' ;
693
797
$ output .= sprintf ('<div class="all test complete">%d units containing %d tests. %d failed assertions. %d passed assertions. %d exceptions. %d incomplete tests. %d skipped tests.</div> ' , $ this ->count (), $ totals ['case_count ' ], $ totals ['fail_count ' ], $ totals ['pass_count ' ], $ totals ['exception_count ' ], $ totals ['incomplete_count ' ], $ totals ['skipped_count ' ]);
694
798
@@ -855,6 +959,10 @@ function out_symbolic()
855
959
$ xunit ->addAttribute ('pass ' , $ summary ['pass_count ' ]);
856
960
$ xunit ->addAttribute ('exception ' , $ summary ['exception_count ' ]);
857
961
$ xunit ->addAttribute ('incomplete ' , $ summary ['incomplete_count ' ]);
962
+ /*
963
+ $coverage = $this->code_coverage[0]; // this part here doesn't work yet.
964
+ $xunit->addAttribute('coverage', $coverage ); // the admin page doesn't do anything with this yet.
965
+ */
858
966
}
859
967
860
968
foreach ($ timers as $ k => $ v ) {
@@ -872,10 +980,15 @@ function out_symbolic()
872
980
return $ xml ->asXML ();
873
981
}
874
982
983
+ function summary ($ test , $ values )
984
+ {
985
+ $ this ->summaries [$ test ] = $ values ;
986
+ }
987
+
875
988
}
876
989
877
990
include HABARI_PATH . '/index.php ' ;
878
991
879
992
endif ;
880
993
881
- ?>
994
+ ?>
0 commit comments