7017
|
1 ## Copyright (C) 2005, 2006, 2007 Paul Kienzle |
5589
|
2 ## |
7016
|
3 ## This file is part of Octave. |
5589
|
4 ## |
7016
|
5 ## Octave is free software; you can redistribute it and/or modify it |
|
6 ## under the terms of the GNU General Public License as published by |
|
7 ## the Free Software Foundation; either version 3 of the License, or (at |
|
8 ## your option) any later version. |
|
9 ## |
|
10 ## Octave is distributed in the hope that it will be useful, but |
|
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 ## General Public License for more details. |
5589
|
14 ## |
|
15 ## You should have received a copy of the GNU General Public License |
7016
|
16 ## along with Octave; see the file COPYING. If not, see |
|
17 ## <http://www.gnu.org/licenses/>. |
5589
|
18 |
|
19 ## -*- texinfo -*- |
|
20 ## @deftypefn {Function File} {} test @var{name} |
|
21 ## @deftypefnx {Function File} {} test @var{name} quiet|normal|verbose |
|
22 ## @deftypefnx {Function File} {} test ('@var{name}', 'quiet|normal|verbose', @var{fid}) |
|
23 ## @deftypefnx {Function File} {} test ([], 'explain', @var{fid}) |
|
24 ## @deftypefnx {Function File} {@var{success} =} test (@dots{}) |
|
25 ## @deftypefnx {Function File} {[@var{n}, @var{max}] =} test (@dots{}) |
|
26 ## @deftypefnx {Function File} {[@var{code}, @var{idx}] =} test ('@var{name}','grabdemo') |
|
27 ## |
|
28 ## Perform tests from the first file in the loadpath matching @var{name}. |
|
29 ## @code{test} can be called as a command or as a function. Called with |
|
30 ## a single argument @var{name}, the tests are run interactively and stop |
|
31 ## after the first error is encountered. |
|
32 ## |
|
33 ## With a second argument the tests which are performed and the amount of |
|
34 ## output is selected. |
|
35 ## |
|
36 ## @table @asis |
|
37 ## @item 'quiet' |
|
38 ## Don't report all the tests as they happen, just the errors. |
|
39 ## |
|
40 ## @item 'normal' |
|
41 ## Report all tests as they happen, but don't do tests which require |
|
42 ## user interaction. |
|
43 ## |
|
44 ## @item 'verbose' |
|
45 ## Do tests which require user interaction. |
|
46 ## @end table |
|
47 ## |
|
48 ## The argument @var{fid} can be used to allow batch processing. Errors |
|
49 ## can be written to the already open file defined by @var{fid}, and |
|
50 ## hopefully when octave crashes this file will tell you what was happening |
|
51 ## when it did. You can use @code{stdout} if you want to see the results as |
|
52 ## they happen. You can also give a file name rather than an @var{fid}, in |
|
53 ## which case the contents of the file will be replaced with the log from |
|
54 ## the current test. |
|
55 ## |
|
56 ## Called with a single output argument @var{success}, @code{test} returns |
6730
|
57 ## true if all of the tests were successful. Called with two output arguments |
7001
|
58 ## @var{n} and @var{max}, the number of successful tests and the total number |
5589
|
59 ## of tests in the file @var{name} are returned. |
|
60 ## |
|
61 ## If the second argument is the string 'grabdemo', the contents of the demo |
|
62 ## blocks are extracted but not executed. Code for all code blocks is |
7001
|
63 ## concatenated and returned as @var{code} with @var{idx} being a vector of |
5589
|
64 ## positions of the ends of the demo blocks. |
|
65 ## |
|
66 ## If the second argument is 'explain', then @var{name} is ignored and an |
|
67 ## explanation of the line markers used is written to the file @var{fid}. |
5642
|
68 ## @seealso{error, assert, fail, demo, example} |
5589
|
69 ## @end deftypefn |
|
70 |
|
71 ## TODO: * Consider using keyword fail rather then error? This allows us |
|
72 ## TODO: to make a functional form of error blocks, which means we |
|
73 ## TODO: can include them in test sections which means that we can use |
|
74 ## TODO: octave flow control for both kinds of tests. |
|
75 |
|
76 ## PKG_ADD: mark_as_command test |
|
77 |
7242
|
78 function [__ret1, __ret2, __ret3, __ret4] = test (__name, __flag, __fid) |
5589
|
79 ## information from test will be introduced by "key" |
|
80 persistent __signal_fail = "!!!!! "; |
|
81 persistent __signal_empty = "????? "; |
|
82 persistent __signal_block = " ***** "; |
|
83 persistent __signal_file = ">>>>> "; |
7242
|
84 persistent __signal_skip = "----- "; |
5589
|
85 |
6730
|
86 __xfail = 0; |
7242
|
87 __xskip = 0; |
6730
|
88 |
6494
|
89 if (nargin < 2 || isempty (__flag)) |
5589
|
90 __flag = "quiet"; |
|
91 endif |
6494
|
92 if (nargin < 3) |
5589
|
93 __fid = []; |
|
94 endif |
6494
|
95 if (nargin < 1 || nargin > 3 |
|
96 || (! ischar (__name) && ! isempty (__name)) || ! ischar (__flag)) |
6046
|
97 print_usage (); |
5589
|
98 endif |
6494
|
99 if (isempty (__name) && (nargin != 3 || ! strcmp (__flag, "explain"))) |
6046
|
100 print_usage (); |
5589
|
101 endif |
6494
|
102 __batch = (! isempty (__fid)); |
5589
|
103 |
|
104 ## decide if error messages should be collected |
|
105 __close_fid = 0; |
|
106 if (__batch) |
6494
|
107 if (ischar (__fid)) |
|
108 __fid = fopen (__fid, "wt"); |
|
109 if (__fid < 0) |
|
110 error ("could not open log file"); |
|
111 endif |
5589
|
112 __close_fid = 1; |
|
113 endif |
|
114 fprintf (__fid, "%sprocessing %s\n", __signal_file, __name); |
5908
|
115 fflush (__fid); |
5589
|
116 else |
|
117 __fid = stdout; |
|
118 endif |
|
119 |
6494
|
120 if (strcmp (__flag, "normal")) |
5589
|
121 __grabdemo = 0; |
|
122 __rundemo = 0; |
|
123 __verbose = __batch; |
6494
|
124 elseif (strcmp (__flag, "quiet")) |
5589
|
125 __grabdemo = 0; |
|
126 __rundemo = 0; |
|
127 __verbose = 0; |
6494
|
128 elseif (strcmp (__flag, "verbose")) |
5589
|
129 __grabdemo = 0; |
|
130 __rundemo = 1; |
|
131 __verbose = 1; |
6494
|
132 elseif (strcmp (__flag, "grabdemo")) |
5589
|
133 __grabdemo = 1; |
|
134 __rundemo = 0; |
|
135 __verbose = 0; |
|
136 __demo_code = ""; |
|
137 __demo_idx = 1; |
6494
|
138 elseif (strcmp (__flag, "explain")) |
|
139 fprintf (__fid, "# %s new test file\n", __signal_file); |
|
140 fprintf (__fid, "# %s no tests in file\n", __signal_empty); |
|
141 fprintf (__fid, "# %s test had an unexpected result\n", __signal_fail); |
|
142 fprintf (__fid, "# %s code for the test\n", __signal_block); |
5589
|
143 fprintf (__fid, "# Search for the unexpected results in the file\n"); |
|
144 fprintf (__fid, "# then page back to find the file name which caused it.\n"); |
|
145 fprintf (__fid, "# The result may be an unexpected failure (in which\n"); |
|
146 fprintf (__fid, "# case an error will be reported) or an unexpected\n"); |
|
147 fprintf (__fid, "# success (in which case no error will be reported).\n"); |
5908
|
148 fflush (__fid); |
6494
|
149 if (__close_fid) |
|
150 fclose(__fid); |
|
151 endif |
5589
|
152 return; |
|
153 else |
6494
|
154 error ("test unknown flag '%s'", __flag); |
5589
|
155 endif |
|
156 |
|
157 ## locate the file to test |
6249
|
158 __file = file_in_loadpath (__name, "all"); |
|
159 if (isempty (__file)) |
6494
|
160 __file = file_in_loadpath (strcat (__name, ".m"), "all"); |
5589
|
161 endif |
|
162 if (isempty (__file)) |
6494
|
163 __file = file_in_loadpath (strcat (__name, ".cc"), "all"); |
6249
|
164 endif |
|
165 if (iscell (__file)) |
6365
|
166 ## If repeats, return first in path. |
|
167 if (isempty (__file)) |
|
168 __file = ""; |
|
169 else |
|
170 __file = __file{1}; |
|
171 endif |
5589
|
172 endif |
|
173 if (isempty (__file)) |
|
174 if (__grabdemo) |
|
175 __ret1 = ""; |
|
176 __ret2 = []; |
|
177 else |
6494
|
178 fprintf (__fid, "%s%s does not exist in path\n", __signal_empty, __name); |
5908
|
179 fflush (__fid); |
6494
|
180 if (nargout > 0) |
|
181 __ret1 = __ret2 = 0; |
|
182 endif |
5589
|
183 endif |
6494
|
184 if (__close_fid) |
|
185 fclose(__fid); |
|
186 endif |
5589
|
187 return; |
|
188 endif |
|
189 |
|
190 ## grab the test code from the file |
|
191 __body = __extract_test_code (__file); |
|
192 |
|
193 if (isempty (__body)) |
|
194 if (__grabdemo) |
|
195 __ret1 = ""; |
|
196 __ret2 = []; |
|
197 else |
6494
|
198 fprintf (__fid, "%s%s has no tests available\n", __signal_empty, __file); |
5908
|
199 fflush (__fid); |
6494
|
200 if (nargout > 0) |
|
201 __ret1 = __ret2 = 0; |
|
202 endif |
5589
|
203 endif |
6494
|
204 if (__close_fid) |
|
205 fclose(__fid); |
|
206 endif |
5589
|
207 return; |
|
208 else |
|
209 ## add a dummy comment block to the end for ease of indexing |
|
210 if (__body (length(__body)) == "\n") |
6494
|
211 __body = sprintf ("\n%s#", __body); |
5589
|
212 else |
6494
|
213 __body = sprintf ("\n%s\n#", __body); |
5589
|
214 endif |
|
215 endif |
|
216 |
|
217 ## chop it up into blocks for evaluation |
6494
|
218 __lineidx = find (__body == "\n"); |
|
219 __blockidx = __lineidx(find (! isspace (__body(__lineidx+1))))+1; |
5589
|
220 |
|
221 ## ready to start tests ... if in batch mode, tell us what is happening |
|
222 if (__verbose) |
6494
|
223 disp (strcat ( __signal_file, __file)); |
5589
|
224 endif |
|
225 |
|
226 ## assume all tests will pass |
|
227 __all_success = 1; |
|
228 |
|
229 ## process each block separately, initially with no shared variables |
|
230 __tests = __successes = 0; |
|
231 __shared = " "; |
|
232 __shared_r = " "; |
|
233 __clear = ""; |
6494
|
234 for __i = 1:length(__blockidx)-1 |
5589
|
235 |
|
236 ## extract the block |
|
237 __block = __body(__blockidx(__i):__blockidx(__i+1)-2); |
|
238 |
|
239 ## let the user/logfile know what is happening |
|
240 if (__verbose) |
|
241 fprintf (__fid, "%s%s\n", __signal_block, __block); |
5908
|
242 fflush (__fid); |
5589
|
243 endif |
|
244 |
|
245 ## split __block into __type and __code |
6494
|
246 __idx = find (! isletter (__block)); |
|
247 if (isempty (__idx)) |
5589
|
248 __type = __block; |
|
249 __code = ""; |
|
250 else |
|
251 __type = __block(1:__idx(1)-1); |
|
252 __code = __block(__idx(1):length(__block)); |
|
253 endif |
|
254 |
|
255 ## assume the block will succeed; |
|
256 __success = 1; |
|
257 __msg = []; |
|
258 |
|
259 ## DEMO |
|
260 ## If in __grabdemo mode, then don't process any other block type. |
|
261 ## So that the other block types don't have to worry about |
|
262 ## this __grabdemo mode, the demo block processor grabs all block |
|
263 ## types and skips those which aren't demo blocks. |
|
264 __isdemo = strcmp (__type, "demo"); |
|
265 if (__grabdemo || __isdemo) |
|
266 __istest = 0; |
|
267 |
|
268 if (__grabdemo && __isdemo) |
|
269 if (isempty(__demo_code)) |
|
270 __demo_code = __code; |
6494
|
271 __demo_idx = [1, length(__demo_code)+1]; |
5589
|
272 else |
|
273 __demo_code = strcat(__demo_code, __code); |
6494
|
274 __demo_idx = [__demo_idx, length(__demo_code)+1]; |
5589
|
275 endif |
|
276 |
|
277 elseif (__rundemo && __isdemo) |
|
278 try |
|
279 ## process the code in an environment without variables |
6494
|
280 eval (sprintf ("function __test__()\n%s\nendfunction", __code)); |
5589
|
281 __test__; |
6494
|
282 input ("Press <enter> to continue: ", "s"); |
5589
|
283 catch |
|
284 __success = 0; |
6494
|
285 __msg = sprintf ("%sdemo failed\n%s", __signal_fail, __error_text__); |
5589
|
286 end_try_catch |
|
287 clear __test__; |
|
288 |
|
289 endif |
|
290 __code = ""; # code already processed |
|
291 |
|
292 ## SHARED |
|
293 elseif strcmp (__type, "shared") |
|
294 __istest = 0; |
|
295 |
|
296 ## separate initialization code from variables |
6494
|
297 __idx = find (__code == "\n"); |
|
298 if (isempty (__idx)) |
5589
|
299 __vars = __code; |
|
300 __code = ""; |
|
301 else |
|
302 __vars = __code (1:__idx(1)-1); |
|
303 __code = __code (__idx(1):length(__code)); |
|
304 endif |
|
305 |
|
306 ## strip comments off the variables |
6730
|
307 __idx = find (__vars == "%" | __vars == "#"); |
6494
|
308 if (! isempty (__idx)) |
5589
|
309 __vars = __vars(1:__idx(1)-1); |
|
310 endif |
|
311 |
|
312 ## assign default values to variables |
|
313 try |
6494
|
314 __vars = deblank (__vars); |
|
315 if (! isempty (__vars)) |
|
316 eval (strcat (strrep (__vars, ",", "=[];"), "=[];")); |
5589
|
317 __shared = __vars; |
6494
|
318 __shared_r = strcat ("[ ", __vars, "] = "); |
5589
|
319 else |
|
320 __shared = " "; |
|
321 __shared_r = " "; |
|
322 endif |
|
323 catch |
|
324 __code = ""; # couldn't declare, so don't initialize |
|
325 __success = 0; |
6494
|
326 __msg = sprintf ("%sshared variable initialization failed\n", |
|
327 __signal_fail); |
5589
|
328 end_try_catch |
|
329 |
|
330 ## clear shared function definitions |
6494
|
331 eval (__clear, ""); |
|
332 __clear = ""; |
5589
|
333 |
|
334 ## initialization code will be evaluated below |
|
335 |
|
336 ## FUNCTION |
6494
|
337 elseif (strcmp (__type, "function")) |
5589
|
338 __istest = 0; |
|
339 persistent __fn = 0; |
6494
|
340 __name_position = function_name (__block); |
|
341 if (isempty (__name_position)) |
5589
|
342 __success = 0; |
6494
|
343 __msg = sprintf ("%stest failed: missing function name\n", |
|
344 __signal_fail); |
5589
|
345 else |
|
346 __name = __block(__name_position(1):__name_position(2)); |
|
347 __code = __block; |
|
348 try |
|
349 eval(__code); ## Define the function |
6494
|
350 __clear = sprintf ("%sclear %s;\n", __clear, __name); |
5589
|
351 catch |
|
352 __success = 0; |
6494
|
353 __msg = sprintf ("%stest failed: syntax error\n%s", |
|
354 __signal_fail, __error_text__); |
5589
|
355 end_try_catch |
|
356 endif |
|
357 __code = ""; |
|
358 |
|
359 |
|
360 ## ASSERT/FAIL |
6494
|
361 elseif (strcmp (__type, "assert") || strcmp (__type, "fail")) |
5589
|
362 __istest = 1; |
|
363 __code = __block; # put the keyword back on the code |
|
364 ## the code will be evaluated below as a test block |
|
365 |
|
366 ## ERROR/WARNING |
6494
|
367 elseif (strcmp (__type, "error") || strcmp(__type, "warning")) |
5589
|
368 __istest = 1; |
6494
|
369 __warning = strcmp (__type, "warning"); |
|
370 [__pattern, __code] = getpattern (__code); |
5589
|
371 try |
6494
|
372 eval (sprintf ("function __test__(%s)\n%s\nendfunction", |
|
373 __shared, __code)); |
5589
|
374 catch |
|
375 __success = 0; |
6494
|
376 __msg = sprintf ("%stest failed: syntax error\n%s", |
|
377 __signal_fail, __error_text__); |
5589
|
378 end_try_catch |
|
379 |
|
380 if (__success) |
|
381 __success = 0; |
6494
|
382 __warnstate = warning ("query", "quiet"); |
|
383 warning ("on", "quiet"); |
5589
|
384 try |
6494
|
385 eval (sprintf ("__test__(%s);", __shared)); |
|
386 if (! __warning) |
|
387 __msg = sprintf ("%sexpected <%s> but got no error\n", |
|
388 __signal_fail, __pattern); |
7028
|
389 else |
|
390 __err = trimerr (lastwarn, "warning"); |
|
391 warning (__warnstate.state, "quiet"); |
|
392 if (isempty (__err)) |
|
393 __msg = sprintf ("%sexpected <%s> but got no warning\n", |
6494
|
394 __signal_fail, __pattern); |
7028
|
395 elseif (isempty (regexp (__err, __pattern, "once"))) |
|
396 __msg = sprintf ("%sexpected <%s> but got %s\n", |
|
397 __signal_fail, __pattern, __err); |
|
398 else |
|
399 __success = 1; |
|
400 endif |
|
401 endif |
5589
|
402 |
|
403 catch |
6494
|
404 __err = trimerr (lasterr, "error"); |
|
405 warning (__warnstate.state, "quiet"); |
|
406 if (__warning) |
|
407 __msg = sprintf ("%sexpected warning <%s> but got error %s\n", |
|
408 __signal_fail, __pattern, __err); |
|
409 elseif (isempty (regexp (__err, __pattern, "once"))) |
|
410 __msg = sprintf ("%sexpected <%s> but got %s\n", |
|
411 __signal_fail, __pattern, __err); |
5589
|
412 else |
|
413 __success = 1; |
|
414 endif |
|
415 end_try_catch |
|
416 clear __test__; |
|
417 endif |
|
418 __code = ""; # code already processed |
|
419 |
7242
|
420 ## TESTIF |
|
421 elseif (strcmp (__type, "testif")) |
|
422 [__e, __feat] = regexp (__code, '^\s*([^\s]+)', 'end', 'tokens'); |
|
423 if (isempty (findstr (octave_config_info ("DEFS"), __feat{1}{1}))) |
|
424 __xskip++; |
|
425 __success = 0; |
|
426 __istest = 0; |
|
427 __code = ""; # skip the code |
|
428 __msg = sprintf ("%sskipped test\n", __signal_skip); |
|
429 else |
|
430 __istest = 1; |
|
431 __code = __code(__e + 1 : end); |
|
432 endif |
|
433 |
5589
|
434 ## TEST |
6728
|
435 elseif (strcmp (__type, "test") || strcmp (__type, "xtest")) |
5589
|
436 __istest = 1; |
|
437 ## code will be evaluated below |
|
438 |
|
439 ## comment block |
6494
|
440 elseif (strcmp (__block(1:1), "#")) |
5589
|
441 __istest = 0; |
|
442 __code = ""; # skip the code |
|
443 |
|
444 else |
|
445 ## unknown block |
|
446 __istest = 1; |
|
447 __success = 0; |
6494
|
448 __msg = sprintf ("%sunknown test type!\n", __signal_fail); |
5589
|
449 __code = ""; # skip the code |
|
450 endif |
|
451 |
|
452 ## evaluate code for test, shared, and assert. |
6494
|
453 if (! isempty(__code)) |
5589
|
454 try |
6494
|
455 eval (sprintf ("function %s__test__(%s)\n%s\nendfunction", |
|
456 __shared_r,__shared, __code)); |
|
457 eval (sprintf ("%s__test__(%s);", __shared_r, __shared)); |
5589
|
458 catch |
6728
|
459 if (strcmp (__type, "xtest")) |
|
460 __msg = sprintf ("%sknown failure\n%s", __signal_fail, __error_text__); |
6730
|
461 __xfail++; |
6728
|
462 else |
|
463 __msg = sprintf ("%stest failed\n%s", __signal_fail, __error_text__); |
|
464 __success = 0; |
|
465 endif |
6494
|
466 if (isempty (__error_text__)) |
|
467 error ("empty error text, probably Ctrl-C --- aborting"); |
5589
|
468 endif |
|
469 end_try_catch |
|
470 clear __test__; |
|
471 endif |
|
472 |
|
473 ## All done. Remember if we were successful and print any messages |
6494
|
474 if (! isempty (__msg)) |
5589
|
475 ## make sure the user knows what caused the error |
6494
|
476 if (! __verbose) |
5589
|
477 fprintf (__fid, "%s%s\n", __signal_block, __block); |
5908
|
478 fflush (__fid); |
5589
|
479 endif |
|
480 fputs (__fid, __msg); |
5908
|
481 fflush (__fid); |
5589
|
482 ## show the variable context |
6494
|
483 if (! strcmp (__type, "error") && ! all (__shared == " ")) |
|
484 fputs (__fid, "shared variables "); |
|
485 eval (sprintf ("fdisp(__fid,bundle(%s));", __shared)); |
5908
|
486 fflush (__fid); |
5589
|
487 endif |
|
488 endif |
|
489 if (__success == 0) |
|
490 __all_success = 0; |
|
491 ## stop after one error if not in batch mode |
6494
|
492 if (! __batch) |
|
493 if (nargout > 0) |
|
494 __ret1 = __ret2 = 0; |
|
495 endif |
|
496 if (__close_fid) |
|
497 fclose(__fid); |
|
498 endif |
5589
|
499 return; |
|
500 endif |
|
501 endif |
|
502 __tests += __istest; |
6494
|
503 __successes += __success * __istest; |
5589
|
504 endfor |
6494
|
505 eval (__clear, ""); |
5589
|
506 |
|
507 if (nargout == 0) |
6730
|
508 if (__xfail) |
|
509 printf ("PASSES %d out of %d tests (%d expected failures)\n", |
|
510 __successes, __tests, __xfail); |
|
511 else |
|
512 printf ("PASSES %d out of %d tests\n", __successes, __tests); |
|
513 endif |
7242
|
514 if (__xskip) |
|
515 printf ("Skipped %d tests due to missing features\n", __xskip); |
|
516 endif |
5589
|
517 elseif (__grabdemo) |
|
518 __ret1 = __demo_code; |
|
519 __ret2 = __demo_idx; |
6494
|
520 elseif (nargout == 1) |
5589
|
521 __ret1 = __all_success; |
|
522 else |
|
523 __ret1 = __successes; |
|
524 __ret2 = __tests; |
6730
|
525 __ret3 = __xfail; |
7242
|
526 __ret4 = __xskip; |
5589
|
527 endif |
|
528 endfunction |
|
529 |
|
530 ## create structure with fieldnames the name of the input variables |
6494
|
531 function s = varstruct (varargin) |
|
532 for i = 1:nargin |
|
533 s.(deblank (argn(i,:))) = varargin{i}; |
5589
|
534 endfor |
|
535 endfunction |
|
536 |
|
537 ## find [start,end] of fn in 'function [a,b] = fn' |
6494
|
538 function pos = function_name (def) |
5589
|
539 pos = []; |
|
540 |
|
541 ## Find the end of the name |
6494
|
542 right = find (def == "(", 1); |
|
543 if (isempty (right)) |
|
544 return; |
|
545 endif |
|
546 right = find (def(1:right-1) != " ", 1, "last"); |
5589
|
547 |
|
548 ## Find the beginning of the name |
6494
|
549 left = max ([find(def(1:right)==" ", 1, "last"), ... |
|
550 find(def(1:right)=="=", 1, "last")]); |
|
551 if (isempty (left)) |
|
552 return; |
|
553 endif |
5589
|
554 left++; |
|
555 |
|
556 ## Return the end points of the name |
6494
|
557 pos = [left, right]; |
5589
|
558 endfunction |
|
559 |
|
560 ## strip <pattern> from '<pattern> code' |
6494
|
561 function [pattern, rest] = getpattern (str) |
|
562 pattern = "."; |
5589
|
563 rest = str; |
6494
|
564 str = trimleft (str); |
|
565 if (! isempty (str) && str(1) == "<") |
|
566 close = index (str, ">"); |
|
567 if (close) |
5589
|
568 pattern = str(2:close-1); |
|
569 rest = str(close+1:end); |
|
570 endif |
|
571 endif |
|
572 endfunction |
|
573 |
|
574 ## strip '.*prefix:' from '.*prefix: msg\n' and strip trailing blanks |
6494
|
575 function msg = trimerr (msg, prefix) |
|
576 idx = index (msg, strcat (prefix, ":")); |
|
577 if (idx > 0) |
|
578 msg(1:idx+length(prefix)) = []; |
|
579 endif |
|
580 msg = trimleft (deblank (msg)); |
5589
|
581 endfunction |
|
582 |
|
583 ## strip leading blanks from string |
6494
|
584 function str = trimleft (str) |
|
585 idx = find (isspace (str)); |
|
586 leading = find (idx == 1:length(idx)); |
|
587 if (! isempty (leading)) |
5589
|
588 str = str(leading(end)+1:end); |
|
589 endif |
|
590 endfunction |
|
591 |
|
592 ## make a structure out of the named variables |
|
593 ## (based on Etienne Grossmann's tar function) |
6494
|
594 function s = bundle (varargin) |
|
595 for i = 1:nargin |
|
596 s.(deblank (argn(i,:))) = varargin{i}; |
7151
|
597 endfor |
5589
|
598 endfunction |
|
599 |
|
600 function body = __extract_test_code (nm) |
|
601 fid = fopen (nm, "rt"); |
|
602 body = []; |
|
603 if (fid >= 0) |
6494
|
604 while (! feof (fid)) |
5589
|
605 ln = fgetl (fid); |
6494
|
606 if (length (ln) >= 2 && strcmp (ln(1:2), "%!")) |
5589
|
607 body = [body, "\n"]; |
|
608 if (length(ln) > 2) |
6494
|
609 body = strcat (body, ln(3:end)); |
5589
|
610 endif |
|
611 endif |
|
612 endwhile |
|
613 fclose (fid); |
|
614 endif |
|
615 endfunction |
|
616 |
7242
|
617 ## Test for test for missing features |
|
618 %!testif OCTAVE_SOURCE |
|
619 %! ## This test should be run |
|
620 %! assert (true); |
|
621 %!testif HAVE_FOOBAR |
|
622 %! ## missing feature. Fail if this test is run |
|
623 %! error("Failed missing feature test"); |
|
624 |
6728
|
625 ### Test for a known failure |
|
626 %!xtest error("This test is known to fail") |
|
627 |
5589
|
628 ### example from toeplitz |
|
629 %!shared msg |
|
630 %! msg="expecting vector arguments"; |
|
631 %!fail ('toeplitz([])', msg); |
|
632 %!fail ('toeplitz([1,2],[])', msg); |
|
633 %!fail ('toeplitz([1,2;3,4])', msg); |
|
634 %!fail ('toeplitz([1,2],[1,2;3,4])', msg); |
|
635 %!fail ('toeplitz ([1,2;3,4],[1,2])', msg); |
|
636 % !fail ('toeplitz','usage: toeplitz'); # usage doesn't generate an error |
|
637 % !fail ('toeplitz(1, 2, 3)', 'usage: toeplitz'); |
|
638 %!test assert (toeplitz ([1,2,3], [1,4]), [1,4; 2,1; 3,2]); |
|
639 %!demo toeplitz ([1,2,3,4],[1,5,6]) |
|
640 |
|
641 ### example from kron |
5775
|
642 %!#error kron # FIXME suppress these until we can handle output |
5589
|
643 %!#error kron(1,2,3) |
|
644 %!test assert (isempty (kron ([], rand(3, 4)))) |
|
645 %!test assert (isempty (kron (rand (3, 4), []))) |
|
646 %!test assert (isempty (kron ([], []))) |
|
647 %!shared A, B |
|
648 %!test |
|
649 %! A = [1, 2, 3; 4, 5, 6]; |
|
650 %! B = [1, -1; 2, -2]; |
|
651 %!assert (size (kron (zeros (3, 0), A)), [ 3*rows(A), 0 ]) |
|
652 %!assert (size (kron (zeros (0, 3), A)), [ 0, 3*columns(A) ]) |
|
653 %!assert (size (kron (A, zeros (3, 0))), [ 3*rows(A), 0 ]) |
|
654 %!assert (size (kron (A, zeros (0, 3))), [ 0, 3*columns(A) ]) |
|
655 %!assert (kron (pi, e), pi*e) |
|
656 %!assert (kron (pi, A), pi*A) |
|
657 %!assert (kron (A, e), e*A) |
|
658 %!assert (kron ([1, 2, 3], A), [ A, 2*A, 3*A ]) |
|
659 %!assert (kron ([1; 2; 3], A), [ A; 2*A; 3*A ]) |
|
660 %!assert (kron ([1, 2; 3, 4], A), [ A, 2*A; 3*A, 4*A ]) |
|
661 %!test |
|
662 %! res = [1,-1,2,-2,3,-3; 2,-2,4,-4,6,-6; 4,-4,5,-5,6,-6; 8,-8,10,-10,12,-12]; |
|
663 %! assert (kron (A, B), res) |
|
664 |
|
665 ### an extended demo from specgram |
|
666 %!#demo |
|
667 %! ## Speech spectrogram |
|
668 %! [x, Fs] = auload(file_in_loadpath("sample.wav")); # audio file |
|
669 %! step = fix(5*Fs/1000); # one spectral slice every 5 ms |
|
670 %! window = fix(40*Fs/1000); # 40 ms data window |
|
671 %! fftn = 2^nextpow2(window); # next highest power of 2 |
|
672 %! [S, f, t] = specgram(x, fftn, Fs, window, window-step); |
|
673 %! S = abs(S(2:fftn*4000/Fs,:)); # magnitude in range 0<f<=4000 Hz. |
|
674 %! S = S/max(max(S)); # normalize magnitude so that max is 0 dB. |
|
675 %! S = max(S, 10^(-40/10)); # clip below -40 dB. |
|
676 %! S = min(S, 10^(-3/10)); # clip above -3 dB. |
|
677 %! imagesc(flipud(20*log10(S)), 1); |
|
678 %! % you should now see a spectrogram in the image window |
|
679 |
|
680 |
|
681 ### now test test itself |
|
682 |
|
683 %!## usage and error testing |
|
684 % !fail ('test','usage.*test') # no args, generates usage() |
|
685 % !fail ('test(1,2,3,4)','usage.*test') # too many args, generates usage() |
|
686 %!fail ('test("test", "bogus")','unknown flag') # incorrect args |
|
687 %!fail ('garbage','garbage.*undefined') # usage on nonexistent function should be |
|
688 |
|
689 %!error <usage.*test> test # no args, generates usage() |
|
690 %!error <usage.*test> test(1,2,3,4) # too many args, generates usage() |
|
691 %!error <unknown flag> test("test", 'bogus'); # incorrect args, generates error() |
|
692 %!error <garbage' undefined> garbage # usage on nonexistent function should be |
|
693 |
|
694 %!error test("test", 'bogus'); # test without pattern |
|
695 |
5681
|
696 %!test |
|
697 %! lastwarn(); # clear last warning just in case |
|
698 |
5781
|
699 %!warning <warning message> warning('warning message'); |
5589
|
700 |
|
701 %!## test of shared variables |
|
702 %!shared a # create a shared variable |
|
703 %!test a=3; # assign to a shared variable |
|
704 %!test assert(a,3) # variable should equal 3 |
|
705 %!shared b,c # replace shared variables |
|
706 %!test assert (!exist("a")); # a no longer exists |
|
707 %!test assert (isempty(b)); # variables start off empty |
|
708 %!shared a,b,c # recreate a shared variable |
|
709 %!test assert (isempty(a)); # value is empty even if it had a previous value |
|
710 %!test a=1; b=2; c=3; # give values to all variables |
|
711 %!test assert ([a,b,c],[1,2,3]); # test all of them together |
|
712 %!test c=6; # update a value |
|
713 %!test assert([a, b, c],[1, 2, 6]); # show that the update sticks |
|
714 %!shared # clear all shared variables |
|
715 %!test assert(!exist("a")) # show that they are cleared |
|
716 %!shared a,b,c # support for initializer shorthand |
|
717 %! a=1; b=2; c=4; |
|
718 |
|
719 %!function x = __test_a(y) |
|
720 %! x = 2*y; |
|
721 %!assert(__test_a(2),4); # Test a test function |
|
722 |
|
723 %!function __test_a (y) |
|
724 %! x = 2*y; |
|
725 %!test |
|
726 %! __test_a(2); # Test a test function with no return value |
|
727 |
|
728 %!function [x,z] = __test_a (y) |
|
729 %! x = 2*y; |
|
730 %! z = 3*y; |
|
731 %!test # Test a test function with multiple returns |
|
732 %! [x,z] = __test_a(3); |
|
733 %! assert(x,6); |
|
734 %! assert(z,9); |
|
735 |
|
736 %!## test of assert block |
|
737 %!assert (isempty([])) # support for test assert shorthand |
|
738 |
|
739 %!## demo blocks |
|
740 %!demo # multiline demo block |
|
741 %! t=[0:0.01:2*pi]; x=sin(t); |
|
742 %! plot(t,x); |
|
743 %! % you should now see a sine wave in your figure window |
|
744 %!demo a=3 # single line demo blocks work too |
|
745 |
|
746 %!## this is a comment block. it can contain anything. |
|
747 %!## |
|
748 %! it is the "#" as the block type that makes it a comment |
|
749 %! and it stays as a comment even through continuation lines |
|
750 %! which means that it works well with commenting out whole tests |
|
751 |
|
752 % !# failure tests. All the following should fail. These tests should |
|
753 % !# be disabled unless you are developing test() since users don't |
|
754 % !# like to be presented with expected failures. I use % ! to disable. |
|
755 % !test error("---------Failure tests. Use test('test','verbose',1)"); |
|
756 % !test assert([a,b,c],[1,3,6]); # variables have wrong values |
|
757 % !bogus # unknown block type |
|
758 % !error toeplitz([1,2,3]); # correct usage |
|
759 % !test syntax errors) # syntax errors fail properly |
|
760 % !shared garbage in # variables must be comma separated |
|
761 % !error syntax++error # error test fails on syntax errors |
|
762 % !error "succeeds."; # error test fails if code succeeds |
|
763 % !error <wrong pattern> error("message") # error pattern must match |
|
764 % !demo with syntax error # syntax errors in demo fail properly |
|
765 % !shared a,b,c |
|
766 % !demo # shared variables not available in demo |
|
767 % ! assert(exist("a")) |
|
768 % !error |
|
769 % ! test('/etc/passwd'); |
|
770 % ! test("nonexistent file"); |
|
771 % ! ## These don't signal an error, so the test for an error fails. Note |
|
772 % ! ## that the call doesn't reference the current fid (it is unavailable), |
|
773 % ! ## so of course the informational message is not printed in the log. |