Index: trunk/phase3/maintenance/parserTests.inc |
— | — | @@ -85,6 +85,9 @@ |
86 | 86 | break; |
87 | 87 | } |
88 | 88 | } |
| 89 | + $this->term = $this->color |
| 90 | + ? new AnsiTermColorer( $this->lightcolor ) |
| 91 | + : new DummyTermColorer(); |
89 | 92 | |
90 | 93 | $this->showDiffs = !isset( $options['quick'] ); |
91 | 94 | $this->quiet = isset( $options['quiet'] ); |
— | — | @@ -99,9 +102,9 @@ |
100 | 103 | } |
101 | 104 | |
102 | 105 | if( isset( $options['record'] ) ) { |
103 | | - $this->recorder = new TestRecorder(); |
| 106 | + $this->recorder = new DbTestRecorder( $this->term ); |
104 | 107 | } else { |
105 | | - $this->recorder = new DummyTestRecorder(); |
| 108 | + $this->recorder = new TestRecorder( $this->term ); |
106 | 109 | } |
107 | 110 | |
108 | 111 | $this->hooks = array(); |
— | — | @@ -122,39 +125,53 @@ |
123 | 126 | } |
124 | 127 | |
125 | 128 | /** |
126 | | - * Run a series of tests listed in the given text file. |
| 129 | + * Run a series of tests listed in the given text files. |
127 | 130 | * Each test consists of a brief description, wikitext input, |
128 | 131 | * and the expected HTML output. |
129 | 132 | * |
130 | 133 | * Prints status updates on stdout and counts up the total |
131 | 134 | * number and percentage of passed tests. |
132 | 135 | * |
133 | | - * @param string $filename |
| 136 | + * @param array of strings $filenames |
134 | 137 | * @return bool True if passed all tests, false if any tests failed. |
135 | 138 | * @public |
136 | 139 | */ |
137 | | - function runTestsFromFile( $filename ) { |
| 140 | + function runTestsFromFiles( $filenames ) { |
| 141 | + $this->recorder->start(); |
| 142 | + $ok = true; |
| 143 | + foreach( $filenames as $filename ) { |
| 144 | + $ok = $this->runFile( $filename ) && $ok; |
| 145 | + } |
| 146 | + $this->recorder->end(); |
| 147 | + $this->recorder->report(); |
| 148 | + return $ok; |
| 149 | + } |
| 150 | + |
| 151 | + private function runFile( $filename ) { |
138 | 152 | $infile = fopen( $filename, 'rt' ); |
139 | 153 | if( !$infile ) { |
140 | 154 | wfDie( "Couldn't open $filename\n" ); |
| 155 | + } else { |
| 156 | + print $this->term->color( 1 ) . |
| 157 | + "Reading tests from \"$filename\"..." . |
| 158 | + $this->term->reset() . |
| 159 | + "\n"; |
141 | 160 | } |
142 | 161 | |
143 | 162 | $data = array(); |
144 | 163 | $section = null; |
145 | | - $success = 0; |
146 | | - $total = 0; |
147 | 164 | $n = 0; |
148 | | - $this->recorder->start(); |
| 165 | + $ok = true; |
149 | 166 | while( false !== ($line = fgets( $infile ) ) ) { |
150 | 167 | $n++; |
151 | 168 | if( preg_match( '/^!!\s*(\w+)/', $line, $matches ) ) { |
152 | 169 | $section = strtolower( $matches[1] ); |
153 | 170 | if( $section == 'endarticle') { |
154 | 171 | if( !isset( $data['text'] ) ) { |
155 | | - wfDie( "'endarticle' without 'text' at line $n\n" ); |
| 172 | + wfDie( "'endarticle' without 'text' at line $n of $filename\n" ); |
156 | 173 | } |
157 | 174 | if( !isset( $data['article'] ) ) { |
158 | | - wfDie( "'endarticle' without 'article' at line $n\n" ); |
| 175 | + wfDie( "'endarticle' without 'article' at line $n of $filename\n" ); |
159 | 176 | } |
160 | 177 | $this->addArticle($this->chomp($data['article']), $this->chomp($data['text']), $n); |
161 | 178 | $data = array(); |
— | — | @@ -163,7 +180,7 @@ |
164 | 181 | } |
165 | 182 | if( $section == 'endhooks' ) { |
166 | 183 | if( !isset( $data['hooks'] ) ) { |
167 | | - wfDie( "'endhooks' without 'hooks' at line $n\n" ); |
| 184 | + wfDie( "'endhooks' without 'hooks' at line $n of $filename\n" ); |
168 | 185 | } |
169 | 186 | foreach( explode( "\n", $data['hooks'] ) as $line ) { |
170 | 187 | $line = trim( $line ); |
— | — | @@ -177,7 +194,7 @@ |
178 | 195 | } |
179 | 196 | if( $section == 'endfunctionhooks' ) { |
180 | 197 | if( !isset( $data['functionhooks'] ) ) { |
181 | | - wfDie( "'endfunctionhooks' without 'functionhooks' at line $n\n" ); |
| 198 | + wfDie( "'endfunctionhooks' without 'functionhooks' at line $n of $filename\n" ); |
182 | 199 | } |
183 | 200 | foreach( explode( "\n", $data['functionhooks'] ) as $line ) { |
184 | 201 | $line = trim( $line ); |
— | — | @@ -191,13 +208,13 @@ |
192 | 209 | } |
193 | 210 | if( $section == 'end' ) { |
194 | 211 | if( !isset( $data['test'] ) ) { |
195 | | - wfDie( "'end' without 'test' at line $n\n" ); |
| 212 | + wfDie( "'end' without 'test' at line $n of $filename\n" ); |
196 | 213 | } |
197 | 214 | if( !isset( $data['input'] ) ) { |
198 | | - wfDie( "'end' without 'input' at line $n\n" ); |
| 215 | + wfDie( "'end' without 'input' at line $n of $filename\n" ); |
199 | 216 | } |
200 | 217 | if( !isset( $data['result'] ) ) { |
201 | | - wfDie( "'end' without 'result' at line $n\n" ); |
| 218 | + wfDie( "'end' without 'result' at line $n of $filename\n" ); |
202 | 219 | } |
203 | 220 | if( !isset( $data['options'] ) ) { |
204 | 221 | $data['options'] = ''; |
— | — | @@ -217,17 +234,14 @@ |
218 | 235 | $this->chomp( $data['input'] ), |
219 | 236 | $this->chomp( $data['result'] ), |
220 | 237 | $this->chomp( $data['options'] ) ); |
221 | | - if( $result ) { |
222 | | - $success++; |
223 | | - } |
224 | | - $total++; |
| 238 | + $ok = $ok && $result; |
225 | 239 | $this->recorder->record( $this->chomp( $data['test'] ), $result ); |
226 | 240 | $data = array(); |
227 | 241 | $section = null; |
228 | 242 | continue; |
229 | 243 | } |
230 | 244 | if ( isset ($data[$section] ) ) { |
231 | | - wfDie( "duplicate section '$section' at line $n\n" ); |
| 245 | + wfDie( "duplicate section '$section' at line $n of $filename\n" ); |
232 | 246 | } |
233 | 247 | $data[$section] = ''; |
234 | 248 | continue; |
— | — | @@ -236,23 +250,8 @@ |
237 | 251 | $data[$section] .= $line; |
238 | 252 | } |
239 | 253 | } |
240 | | - $this->recorder->end(); |
241 | | - |
242 | 254 | print "\n"; |
243 | | - $this->recorder->report(); |
244 | | - if( $total > 0 ) { |
245 | | - $ratio = wfPercent( 100 * $success / $total ); |
246 | | - print $this->termColor( 1 ) . "Passed $success of $total tests ($ratio) "; |
247 | | - if( $success == $total ) { |
248 | | - print $this->termColor( 32 ) . "PASSED!"; |
249 | | - } else { |
250 | | - print $this->termColor( 31 ) . "FAILED!"; |
251 | | - } |
252 | | - print $this->termReset() . "\n"; |
253 | | - return ($success == $total); |
254 | | - } else { |
255 | | - wfDie( "No tests found.\n" ); |
256 | | - } |
| 255 | + return $ok; |
257 | 256 | } |
258 | 257 | |
259 | 258 | /** |
— | — | @@ -604,7 +603,7 @@ |
605 | 604 | */ |
606 | 605 | function showSuccess( $desc ) { |
607 | 606 | if( !$this->quiet ) { |
608 | | - print $this->termColor( '1;32' ) . 'PASSED' . $this->termReset() . "\n"; |
| 607 | + print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n"; |
609 | 608 | } |
610 | 609 | return true; |
611 | 610 | } |
— | — | @@ -625,7 +624,7 @@ |
626 | 625 | # test, in case it succeeded. Show it now: |
627 | 626 | $this->showTesting( $desc ); |
628 | 627 | } |
629 | | - print $this->termColor( '1;31' ) . 'FAILED!' . $this->termReset() . "\n"; |
| 628 | + print $this->term->color( '1;31' ) . 'FAILED!' . $this->term->reset() . "\n"; |
630 | 629 | if ( $this->showOutput ) { |
631 | 630 | print "--- Expected ---\n$result\n--- Actual ---\n$html\n"; |
632 | 631 | } |
— | — | @@ -679,33 +678,6 @@ |
680 | 679 | } |
681 | 680 | |
682 | 681 | /** |
683 | | - * Return ANSI terminal escape code for changing text attribs/color, |
684 | | - * or empty string if color output is disabled. |
685 | | - * |
686 | | - * @param string $color Semicolon-separated list of attribute/color codes |
687 | | - * @return string |
688 | | - * @private |
689 | | - */ |
690 | | - function termColor( $color ) { |
691 | | - if($this->lightcolor) { |
692 | | - return $this->color ? "\x1b[1;{$color}m" : ''; |
693 | | - } else { |
694 | | - return $this->color ? "\x1b[{$color}m" : ''; |
695 | | - } |
696 | | - } |
697 | | - |
698 | | - /** |
699 | | - * Return ANSI terminal escape code for restoring default text attributes, |
700 | | - * or empty string if color output is disabled. |
701 | | - * |
702 | | - * @return string |
703 | | - * @private |
704 | | - */ |
705 | | - function termReset() { |
706 | | - return $this->color ? "\x1b[0m" : ''; |
707 | | - } |
708 | | - |
709 | | - /** |
710 | 682 | * Colorize unified diff output if set for ANSI color output. |
711 | 683 | * Subtractions are colored blue, additions red. |
712 | 684 | * |
— | — | @@ -716,8 +688,8 @@ |
717 | 689 | function colorDiff( $text ) { |
718 | 690 | return preg_replace( |
719 | 691 | array( '/^(-.*)$/m', '/^(\+.*)$/m' ), |
720 | | - array( $this->termColor( 34 ) . '$1' . $this->termReset(), |
721 | | - $this->termColor( 31 ) . '$1' . $this->termReset() ), |
| 692 | + array( $this->term->color( 34 ) . '$1' . $this->term->reset(), |
| 693 | + $this->term->color( 31 ) . '$1' . $this->term->reset() ), |
722 | 694 | $text ); |
723 | 695 | } |
724 | 696 | |
— | — | @@ -821,35 +793,79 @@ |
822 | 794 | $start = max( 0, $position - 10 ); |
823 | 795 | $before = $position - $start; |
824 | 796 | $fragment = '...' . |
825 | | - $this->termColor( 34 ) . |
| 797 | + $this->term->color( 34 ) . |
826 | 798 | substr( $text, $start, $before ) . |
827 | | - $this->termColor( 0 ) . |
828 | | - $this->termColor( 31 ) . |
829 | | - $this->termColor( 1 ) . |
| 799 | + $this->term->color( 0 ) . |
| 800 | + $this->term->color( 31 ) . |
| 801 | + $this->term->color( 1 ) . |
830 | 802 | substr( $text, $position, 1 ) . |
831 | | - $this->termColor( 0 ) . |
832 | | - $this->termColor( 34 ) . |
| 803 | + $this->term->color( 0 ) . |
| 804 | + $this->term->color( 34 ) . |
833 | 805 | substr( $text, $position + 1, 9 ) . |
834 | | - $this->termColor( 0 ) . |
| 806 | + $this->term->color( 0 ) . |
835 | 807 | '...'; |
836 | 808 | $display = str_replace( "\n", ' ', $fragment ); |
837 | 809 | $caret = ' ' . |
838 | 810 | str_repeat( ' ', $before ) . |
839 | | - $this->termColor( 31 ) . |
| 811 | + $this->term->color( 31 ) . |
840 | 812 | '^' . |
841 | | - $this->termColor( 0 ); |
| 813 | + $this->term->color( 0 ); |
842 | 814 | return "$display\n$caret"; |
843 | 815 | } |
844 | 816 | |
845 | 817 | } |
846 | 818 | |
847 | | -class DummyTestRecorder { |
| 819 | +class AnsiTermColorer { |
| 820 | + function __construct( $light ) { |
| 821 | + $this->light = $light; |
| 822 | + } |
| 823 | + |
| 824 | + /** |
| 825 | + * Return ANSI terminal escape code for changing text attribs/color |
| 826 | + * |
| 827 | + * @param string $color Semicolon-separated list of attribute/color codes |
| 828 | + * @return string |
| 829 | + * @private |
| 830 | + */ |
| 831 | + function color( $color ) { |
| 832 | + $light = $this->light ? "1;" : ""; |
| 833 | + return "\x1b[{$light}{$color}m"; |
| 834 | + } |
| 835 | + |
| 836 | + /** |
| 837 | + * Return ANSI terminal escape code for restoring default text attributes |
| 838 | + * |
| 839 | + * @return string |
| 840 | + * @private |
| 841 | + */ |
| 842 | + function reset() { |
| 843 | + return "\x1b[0m"; |
| 844 | + } |
| 845 | +} |
| 846 | + |
| 847 | +class DummyTermColorer { |
| 848 | + function color( $color ) { |
| 849 | + return ''; |
| 850 | + } |
| 851 | + |
| 852 | + function reset() { |
| 853 | + return ''; |
| 854 | + } |
| 855 | +} |
| 856 | + |
| 857 | +class TestRecorder { |
| 858 | + function __construct( $term ) { |
| 859 | + $this->term = $term; |
| 860 | + } |
| 861 | + |
848 | 862 | function start() { |
849 | | - // dummy |
| 863 | + $this->total = 0; |
| 864 | + $this->success = 0; |
850 | 865 | } |
851 | 866 | |
852 | 867 | function record( $test, $result ) { |
853 | | - // dummy |
| 868 | + $this->total++; |
| 869 | + $this->success += ($result ? 1 : 0); |
854 | 870 | } |
855 | 871 | |
856 | 872 | function end() { |
— | — | @@ -857,16 +873,33 @@ |
858 | 874 | } |
859 | 875 | |
860 | 876 | function report() { |
861 | | - // dummy |
| 877 | + if( $this->total > 0 ) { |
| 878 | + $this->reportPercentage( $this->success, $this->total ); |
| 879 | + } else { |
| 880 | + wfDie( "No tests found.\n" ); |
| 881 | + } |
862 | 882 | } |
| 883 | + |
| 884 | + function reportPercentage( $success, $total ) { |
| 885 | + $ratio = wfPercent( 100 * $success / $total ); |
| 886 | + print $this->term->color( 1 ) . "Passed $success of $total tests ($ratio) "; |
| 887 | + if( $success == $total ) { |
| 888 | + print $this->term->color( 32 ) . "PASSED!"; |
| 889 | + } else { |
| 890 | + print $this->term->color( 31 ) . "FAILED!"; |
| 891 | + } |
| 892 | + print $this->term->reset() . "\n"; |
| 893 | + return ($success == $total); |
| 894 | + } |
863 | 895 | } |
864 | 896 | |
865 | | -class TestRecorder { |
| 897 | +class DbTestRecorder extends TestRecorder { |
866 | 898 | var $db; ///< Database connection to the main DB |
867 | 899 | var $curRun; ///< run ID number for the current run |
868 | 900 | var $prevRun; ///< run ID number for the previous run, if any |
869 | 901 | |
870 | | - function __construct() { |
| 902 | + function __construct( $term ) { |
| 903 | + parent::__construct( $term ); |
871 | 904 | $this->db = wfGetDB( DB_MASTER ); |
872 | 905 | } |
873 | 906 | |
— | — | @@ -875,6 +908,8 @@ |
876 | 909 | * and all that fun stuff |
877 | 910 | */ |
878 | 911 | function start() { |
| 912 | + parent::start(); |
| 913 | + |
879 | 914 | $this->db->begin(); |
880 | 915 | |
881 | 916 | // We'll make comparisons against the previous run later... |
— | — | @@ -898,6 +933,7 @@ |
899 | 934 | * @param bool $result |
900 | 935 | */ |
901 | 936 | function record( $test, $result ) { |
| 937 | + parent::record( $test, $result ); |
902 | 938 | $this->db->insert( 'testitem', |
903 | 939 | array( |
904 | 940 | 'ti_run' => $this->curRun, |
— | — | @@ -912,6 +948,7 @@ |
913 | 949 | */ |
914 | 950 | function end() { |
915 | 951 | $this->db->commit(); |
| 952 | + parent::end(); |
916 | 953 | } |
917 | 954 | |
918 | 955 | function report() { |
— | — | @@ -935,6 +972,7 @@ |
936 | 973 | } else { |
937 | 974 | print "No previous test runs to compare against.\n"; |
938 | 975 | } |
| 976 | + parent::report(); |
939 | 977 | } |
940 | 978 | |
941 | 979 | /** |
Index: trunk/phase3/maintenance/parserTests.php |
— | — | @@ -54,13 +54,12 @@ |
55 | 55 | $tester = new ParserTest(); |
56 | 56 | |
57 | 57 | if( isset( $options['file'] ) ) { |
58 | | - $file = $options['file']; |
| 58 | + $files = array( $options['file'] ); |
59 | 59 | } else { |
60 | | - # Note: the command line setup changes the current working directory |
61 | | - # to the parent, which is why we have to put the subdir here: |
62 | | - $file = $IP.'/maintenance/parserTests.txt'; |
| 60 | + // Default parser tests and any set from extensions or local config |
| 61 | + $files = $wgParserTestFiles; |
63 | 62 | } |
64 | | -$ok = $tester->runTestsFromFile( $file ); |
| 63 | +$ok = $tester->runTestsFromFiles( $files ); |
65 | 64 | |
66 | 65 | exit ($ok ? 0 : -1); |
67 | 66 | ?> |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -2308,4 +2308,17 @@ |
2309 | 2309 | $wgEnableAPI = true; |
2310 | 2310 | $wgEnableWriteAPI = false; |
2311 | 2311 | |
| 2312 | +/** |
| 2313 | + * Parser test suite files to be run by parserTests.php when no specific |
| 2314 | + * filename is passed to it. |
| 2315 | + * |
| 2316 | + * Extensions may add their own tests to this array, or site-local tests |
| 2317 | + * may be added via LocalSettings.php |
| 2318 | + * |
| 2319 | + * Use full paths. |
| 2320 | + */ |
| 2321 | +$wgParserTestFiles = array( |
| 2322 | + "$IP/maintenance/parserTests.txt", |
| 2323 | +); |
| 2324 | + |
2312 | 2325 | ?> |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -167,8 +167,11 @@ |
168 | 168 | compare changes against the previous run. |
169 | 169 | Additional tables 'testrun' and 'testitem' are in maintenance/testRunner.sql, |
170 | 170 | source this and pass --record option to parserTests.php |
| 171 | +* Make the set of default parser test input files extensible via |
| 172 | + $wgParserTestFiles. This can now be appended to by extensions or local |
| 173 | + configuration files so that extension or custom tests can be automatically |
| 174 | + run along with the main batch. |
171 | 175 | |
172 | | - |
173 | 176 | == Languages updated == |
174 | 177 | |
175 | 178 | * Bishnupriya Manipuri (bpy) |
Index: trunk/extensions/Cite/Cite.php |
— | — | @@ -26,6 +26,7 @@ |
27 | 27 | 'description' => 'adds <nowiki><ref[ name=id]></nowiki> and <nowiki><references/></nowiki> tags, for citations', |
28 | 28 | 'url' => 'http://meta.wikimedia.org/wiki/Cite/Cite.php' |
29 | 29 | ); |
| 30 | +$wgParserTestFiles[] = dirname( __FILE__ ) . "/citeParserTests.txt"; |
30 | 31 | |
31 | 32 | /** |
32 | 33 | * Error codes, first array = internal errors; second array = user errors |