Mercurial > hg > octave-lyh
comparison scripts/testfun/assert.m @ 17258:afd235a206a2
Allow vector/matrix tolerance and improve error messages for assert.m script
* assert.m
(assert): Document non-scalar tolerance option. Remove FIXME about format of
output. Remove 'coda' and 'iserror' spanning whole routine. Use structure
'err.index/expected/observed/reason' to keep track of multiple results and
recursions. Add persistent variables 'errmsg', 'assert_call_depth' and
'assert_error_occurred' to allow recursions and print only when all complete.
Place output formating in pprint() function. Construct vector tolerance from
scalar tolerance. Add test illustrating recursions and multiple tables. Add
test illustrating variable tolerance. Add test illustrating multidimensional
matrices. Remove looping for constructing error information. Add thorough
tests for exceptional values by checking both real and imaginary. Place zeros
where exceptional values exist in real and imaginary parts of the two matrices.
Add tests illustrating exceptional values in real and/or imaginary part and
numerical mismatch in the other part.
(construct_indeces): Format linear indexing as tuple indexing, vectors (#),
scalars ().
(pprint): Sub function to format and print input command, index of failure,
expected and observed values at failure, and the reason for failure.
author | Daniel J Sebald <daniel.sebald@ieee.org> |
---|---|
date | Mon, 12 Aug 2013 15:44:40 -0500 |
parents | d6499c14021c |
children | 684ccccbc15d |
comparison
equal
deleted
inserted
replaced
17257:923ce8b42db2 | 17258:afd235a206a2 |
---|---|
45 ## If @var{tol} is positive then it is an absolute tolerance which will produce | 45 ## If @var{tol} is positive then it is an absolute tolerance which will produce |
46 ## an error if @code{abs (@var{observed} - @var{expected}) > abs (@var{tol})}. | 46 ## an error if @code{abs (@var{observed} - @var{expected}) > abs (@var{tol})}. |
47 ## If @var{tol} is negative then it is a relative tolerance which will produce | 47 ## If @var{tol} is negative then it is a relative tolerance which will produce |
48 ## an error if @code{abs (@var{observed} - @var{expected}) > | 48 ## an error if @code{abs (@var{observed} - @var{expected}) > |
49 ## abs (@var{tol} * @var{expected})}. If @var{expected} is zero @var{tol} will | 49 ## abs (@var{tol} * @var{expected})}. If @var{expected} is zero @var{tol} will |
50 ## always be interpreted as an absolute tolerance. | 50 ## always be interpreted as an absolute tolerance. If @var{tol} is not scalar |
51 ## its dimensions must agree with those of @var{observed} and @var{expected} | |
52 ## and tests are performed on an element-wise basis. | |
51 ## @end table | 53 ## @end table |
52 ## @seealso{test, fail, error} | 54 ## @seealso{test, fail, error} |
53 ## @end deftypefn | 55 ## @end deftypefn |
54 | 56 |
55 ## FIXME: Output throttling: don't print out the entire 100x100 matrix, | |
56 ## but instead give a summary; don't print out the whole list, just | |
57 ## say what the first different element is, etc. To do this, make | |
58 ## the message generation type specific. | |
59 | |
60 function assert (cond, varargin) | 57 function assert (cond, varargin) |
58 | |
59 if (exist ("assert_call_depth", "var")) | |
60 assert_call_depth++; | |
61 else | |
62 persistent assert_call_depth = 0; | |
63 persistent assert_error_occurred; | |
64 assert_error_occurred = 0; | |
65 persistent errmsg; | |
66 errmsg = ""; | |
67 end | |
61 | 68 |
62 in = deblank (argn(1,:)); | 69 in = deblank (argn(1,:)); |
63 for i = 2:rows (argn) | 70 for i = 2:rows (argn) |
64 in = [in "," deblank(argn(i,:))]; | 71 in = [in "," deblank(argn(i,:))]; |
65 endfor | 72 endfor |
88 | 95 |
89 if (exist ("argn") == 0) | 96 if (exist ("argn") == 0) |
90 argn = " "; | 97 argn = " "; |
91 endif | 98 endif |
92 | 99 |
93 coda = ""; | 100 ## Add to lists as the errors accumulate. If empty at end then no erros. |
94 iserror = 0; | 101 err.index = {}; |
95 | 102 err.observed = {}; |
103 err.expected = {}; | |
104 err.reason = {}; | |
96 | 105 |
97 if (ischar (expected)) | 106 if (ischar (expected)) |
98 iserror = (! ischar (cond) || ! strcmp (cond, expected)); | 107 if (! ischar (cond)) |
99 | 108 err.index{end + 1} = "[]"; |
109 err.expected{end + 1} = expected; | |
110 if (isnumeric (cond)) | |
111 err.observed{end + 1} = num2str (cond); | |
112 err.reason{end + 1} = "Expected string, but observed number"; | |
113 elseif (iscell (cond)) | |
114 err.observed{end + 1} = "{}"; | |
115 err.reason{end + 1} = "Expected string, but observed cell"; | |
116 else | |
117 err.observed{end + 1} = "[]"; | |
118 err.reason{end + 1} = "Expected string, but observed struct"; | |
119 end | |
120 elseif (! strcmp (cond, expected)) | |
121 err.index{end + 1} = "[]"; | |
122 err.observed{end + 1} = cond; | |
123 err.expected{end + 1} = expected; | |
124 err.reason{end + 1} = "Strings don't match"; | |
125 endif | |
100 elseif (iscell (expected)) | 126 elseif (iscell (expected)) |
101 if (! iscell (cond) || any (size (cond) != size (expected))) | 127 if (! iscell (cond) || any (size (cond) != size (expected))) |
102 iserror = 1; | 128 err.index{end + 1} = "{}"; |
129 err.observed{end + 1} = "O"; | |
130 err.expected{end + 1} = "E"; | |
131 err.reason{end + 1} = "Cell sizes don't match"; | |
103 else | 132 else |
104 try | 133 try |
105 for i = 1:length (expected(:)) | 134 for i = 1:length (expected(:)) |
106 assert (cond{i}, expected{i}, tol); | 135 assert (cond{i}, expected{i}, tol); |
107 endfor | 136 endfor |
108 catch | 137 catch |
109 iserror = 1; | 138 err.index{end + 1} = "{}"; |
139 err.observed{end + 1} = "O"; | |
140 err.expected{end + 1} = "E"; | |
141 err.reason{end + 1} = "Cell configuration error"; | |
110 end_try_catch | 142 end_try_catch |
111 endif | 143 endif |
112 | 144 |
113 elseif (isstruct (expected)) | 145 elseif (isstruct (expected)) |
114 if (! isstruct (cond) || any (size (cond) != size (expected)) | 146 if (! isstruct (cond) || any (size (cond) != size (expected)) |
115 || rows (fieldnames (cond)) != rows (fieldnames (expected))) | 147 || rows (fieldnames (cond)) != rows (fieldnames (expected))) |
116 iserror = 1; | 148 err.index{end + 1} = "{}"; |
149 err.observed{end + 1} = "O"; | |
150 err.expected{end + 1} = "E"; | |
151 err.reason{end + 1} = "Structure sizes don't match"; | |
117 else | 152 else |
118 try | 153 try |
119 #empty = numel (cond) == 0; | 154 #empty = numel (cond) == 0; |
120 empty = isempty (cond); | 155 empty = isempty (cond); |
121 normal = (numel (cond) == 1); | 156 normal = (numel (cond) == 1); |
122 for [v, k] = cond | 157 for [v, k] = cond |
123 if (! isfield (expected, k)) | 158 if (! isfield (expected, k)) |
124 error (); | 159 err.index{end + 1} = "."; |
160 err.observed{end + 1} = "O"; | |
161 err.expected{end + 1} = "E"; | |
162 err.reason{end + 1} = ["'" k "'" " is not an expected field"]; | |
125 endif | 163 endif |
126 if (empty) | 164 if (empty) |
127 v = {}; | 165 v = {}; |
128 elseif (normal) | 166 elseif (normal) |
129 v = {v}; | 167 v = {v}; |
131 v = v(:)'; | 169 v = v(:)'; |
132 endif | 170 endif |
133 assert (v, {expected.(k)}, tol); | 171 assert (v, {expected.(k)}, tol); |
134 endfor | 172 endfor |
135 catch | 173 catch |
136 iserror = 1; | 174 err.index{end + 1} = "."; |
175 err.observed{end + 1} = "O"; | |
176 err.expected{end + 1} = "E"; | |
177 err.reason{end + 1} = "Structure configuration error"; | |
137 end_try_catch | 178 end_try_catch |
138 endif | 179 endif |
139 | 180 |
140 elseif (ndims (cond) != ndims (expected) | 181 elseif (ndims (cond) != ndims (expected) |
141 || any (size (cond) != size (expected))) | 182 || any (size (cond) != size (expected))) |
142 iserror = 1; | 183 err.index{end + 1} = "."; |
143 coda = "Dimensions don't match"; | 184 err.observed{end + 1} = ["O(" (sprintf ("%dx", size (cond)) (1:end-1)) ")"]; |
185 err.expected{end + 1} = ["E(" (sprintf ("%dx", size (expected)) (1:end-1)) ")"]; | |
186 err.reason{end + 1} = "Dimensions don't match"; | |
144 | 187 |
145 else | 188 else |
146 if (nargin < 3) | 189 if (nargin < 3) |
147 ## Without explicit tolerance, be more strict. | 190 ## Without explicit tolerance, be more strict. |
148 if (! strcmp (class (cond), class (expected))) | 191 if (! strcmp (class (cond), class (expected))) |
149 iserror = 1; | 192 err.index{end + 1} = "()"; |
150 coda = ["Class " class (cond) " != " class(expected)]; | 193 err.observed{end + 1} = "O"; |
194 err.expected{end + 1} = "E"; | |
195 err.reason{end + 1} = cstrcat("Class ", class (cond), " != ", class(expected)); | |
151 elseif (isnumeric (cond)) | 196 elseif (isnumeric (cond)) |
152 if (issparse (cond) != issparse (expected)) | 197 if (issparse (cond) != issparse (expected)) |
198 err.index{end + 1} = "()"; | |
199 err.observed{end + 1} = "O"; | |
200 err.expected{end + 1} = "E"; | |
153 if (issparse (cond)) | 201 if (issparse (cond)) |
154 iserror = 1; | 202 err.reason{end + 1} = "sparse != non-sparse"; |
155 coda = "sparse != non-sparse"; | |
156 else | 203 else |
157 iserror = 1; | 204 err.reason{end + 1} = "non-sparse != sparse"; |
158 coda = "non-sparse != sparse"; | |
159 endif | 205 endif |
160 elseif (iscomplex (cond) != iscomplex (expected)) | 206 elseif (iscomplex (cond) != iscomplex (expected)) |
161 if (iscomplex (cond)) | 207 err.index{end + 1} = "()"; |
162 iserror = 1; | 208 err.observed{end + 1} = "O"; |
163 coda = "complex != real"; | 209 err.expected{end + 1} = "E"; |
210 if (iscomplex (cond)) | |
211 err.reason{end + 1} = "complex != real"; | |
164 else | 212 else |
165 iserror = 1; | 213 err.reason{end + 1} = "real != complex"; |
166 coda = "real != complex"; | |
167 endif | 214 endif |
168 endif | 215 endif |
169 endif | 216 endif |
170 endif | 217 endif |
171 | 218 |
172 if (! iserror) | 219 if (isempty (err.index)) |
220 | |
173 ## Numeric. | 221 ## Numeric. |
174 A = cond(:); | 222 A = cond; |
175 B = expected(:); | 223 B = expected; |
224 | |
176 ## Check exceptional values. | 225 ## Check exceptional values. |
177 if (any (isna (A) != isna (B))) | 226 erridx = find (isna (real (A)) != isna (real (B)) | isna (imag (A)) != isna (imag (B))); |
178 iserror = 1; | 227 if (! isempty (erridx)) |
179 coda = "NAs don't match"; | 228 err.index (end + 1:end + length (erridx)) = construct_indeces (size (A), erridx); |
180 elseif (any (isnan (A) != isnan (B))) | 229 err.observed (end + 1:end + length (erridx)) = ... |
181 iserror = 1; | 230 strtrim (cellstr (num2str (A (erridx) (:)))); |
182 coda = "NaNs don't match"; | 231 err.expected (end + 1:end + length (erridx)) = ... |
183 ## Try to avoid problems comparing strange values like Inf+NaNi. | 232 strtrim (cellstr (num2str (B (erridx) (:)))); |
184 elseif (any (isinf (A) != isinf (B)) | 233 err.reason (end + 1:end + length (erridx)) = cellstr (repmat ("'NA' mismatch", length (erridx), 1)); |
185 || any (A(isinf (A) & ! isnan (A)) != B(isinf (B) & ! isnan (B)))) | 234 endif |
186 iserror = 1; | 235 |
187 coda = "Infs don't match"; | 236 erridx = find (isnan (real (A)) != isnan (real (B)) | isnan (imag (A)) != isnan (imag (B))); |
237 if (! isempty (erridx)) | |
238 err.index (end + 1:end + length (erridx)) = construct_indeces (size (A), erridx); | |
239 err.observed (end + 1:end + length (erridx)) = ... | |
240 strtrim (cellstr (num2str (A (erridx) (:)))); | |
241 err.expected (end + 1:end + length (erridx)) = ... | |
242 strtrim (cellstr (num2str (B (erridx) (:)))); | |
243 err.reason (end + 1:end + length (erridx)) = cellstr (repmat ("'NaN' mismatch", length (erridx), 1)); | |
244 endif | |
245 | |
246 erridx = find (((isinf (real (A)) | isinf (real (B))) & real (A) != real (B)) | ... | |
247 ((isinf (imag (A)) | isinf (imag (B))) & imag (A) != imag (B))); | |
248 if (! isempty (erridx)) | |
249 err.index (end + 1:end + length (erridx)) = construct_indeces (size (A), erridx); | |
250 err.observed (end + 1:end + length (erridx)) = ... | |
251 strtrim (cellstr (num2str (A (erridx) (:)))); | |
252 err.expected (end + 1:end + length (erridx)) = ... | |
253 strtrim (cellstr (num2str (B (erridx) (:)))); | |
254 err.reason (end + 1:end + length (erridx)) = cellstr (repmat ("'Inf' mismatch", length (erridx), 1)); | |
255 endif | |
256 | |
257 ## Check normal values. Replace all exceptional values by zero. | |
258 A_null_real = real (A); | |
259 B_null_real = real (B); | |
260 exclude = ! isfinite (A_null_real) & ! isfinite (B_null_real); | |
261 A_null_real (exclude) = 0; | |
262 B_null_real (exclude) = 0; | |
263 A_null_imag = imag (A); | |
264 B_null_imag = imag (B); | |
265 exclude = ! isfinite (A_null_real) & ! isfinite (B_null_real); | |
266 A_null_imag (exclude) = 0; | |
267 B_null_imag (exclude) = 0; | |
268 A_null = complex (A_null_real, A_null_imag); | |
269 B_null = complex (B_null_real, B_null_imag); | |
270 if (isscalar (tol)) | |
271 mtol = ones (size (A)) * tol; | |
188 else | 272 else |
189 ## Check normal values. | 273 mtol = tol; |
190 A = A(isfinite (A)); | 274 endif |
191 B = B(isfinite (B)); | 275 |
192 if (tol == 0) | 276 k = (mtol == 0 & isfinite (A_null) & isfinite (B_null)); |
193 err = any (A != B); | 277 erridx = find (A_null != B_null & k); |
194 errtype = "values do not match"; | 278 if (! isempty (erridx)) |
195 elseif (tol >= 0) | 279 err.index (end + 1:end + length (erridx)) = ... |
196 err = max (abs (A - B)); | 280 construct_indeces (size (A), erridx); |
197 errtype = "maximum absolute error %g exceeds tolerance %g"; | 281 err.observed (end + 1:end + length (erridx)) = ... |
198 else | 282 strtrim (cellstr (num2str (A (erridx) (:)))); |
199 abserr = max (abs (A(B == 0))); | 283 err.expected (end + 1:end + length (erridx)) = ... |
200 A = A(B != 0); | 284 strtrim (cellstr (num2str (B (erridx) (:)))); |
201 B = B(B != 0); | 285 err.reason (end + 1:end + length (erridx)) = ... |
202 relerr = max (abs (A - B) ./ abs (B)); | 286 strsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... |
203 err = max ([abserr; relerr]); | 287 [(abs (A_null (erridx) - B_null (erridx))) (mtol (erridx))]')), "\n"); |
204 errtype = "maximum relative error %g exceeds tolerance %g"; | 288 endif |
289 | |
290 k = (mtol > 0 & isfinite (A_null) & isfinite (B_null)); | |
291 erridx = find (abs (A_null - B_null) > mtol & k); | |
292 if (! isempty (erridx)) | |
293 err.index (end + 1:end + length (erridx)) = ... | |
294 construct_indeces (size (A), erridx); | |
295 err.observed (end + 1:end + length (erridx)) = ... | |
296 strtrim (cellstr (num2str (A (erridx) (:)))); | |
297 err.expected (end + 1:end + length (erridx)) = ... | |
298 strtrim (cellstr (num2str (B (erridx) (:)))); | |
299 err.reason (end + 1:end + length (erridx)) = ... | |
300 strsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... | |
301 [(abs (A_null (erridx) - B_null (erridx))) (mtol (erridx))]')), "\n"); | |
302 endif | |
303 | |
304 k = (mtol < 0); | |
305 if (any (k)) | |
306 AA = A_null (k); | |
307 BB = B_null (k); | |
308 abserr = max (abs (AA(BB == 0))); | |
309 AA = AA(BB != 0); | |
310 BB = BB(BB != 0); | |
311 relerr = max (abs (AA - BB) ./ abs (BB)); | |
312 maxerr = max ([abserr; relerr]); | |
313 if (maxerr > abs (tol)) | |
314 err.index{end + 1} = "()"; | |
315 err.observed{end + 1} = "O"; | |
316 err.expected{end + 1} = "E"; | |
317 err.reason{end + 1} = sprintf ("Max rel err %g exceeds tol %g", maxerr, abs (tol)); | |
205 endif | 318 endif |
206 if (err > abs (tol)) | |
207 iserror = 1; | |
208 coda = sprintf (errtype, err, abs (tol)); | |
209 endif | |
210 endif | 319 endif |
211 endif | 320 endif |
212 | 321 |
213 endif | 322 endif |
214 | 323 |
215 if (! iserror) | 324 ## Print any errors |
216 return; | 325 if (! isempty (err.index)) |
326 assert_error_occurred = 1; | |
327 if (! isempty (errmsg)) | |
328 errmsg = cstrcat (errmsg, "\n"); | |
329 endif | |
330 errmsg = cstrcat (errmsg, pprint (in, err)); | |
331 end | |
332 | |
333 endif | |
334 | |
335 if (assert_call_depth == 0) | |
336 | |
337 ## Remove from the variable space to indicate end of recursion | |
338 clear -v assert_call_depth; | |
339 | |
340 ## Last time through. If there were any errors on any pass, raise a flag. | |
341 if (assert_error_occurred) | |
342 error ("%s", errmsg); | |
217 endif | 343 endif |
218 | 344 |
219 ## Pretty print the "expected but got" info, trimming leading and | 345 else |
220 ## trailing "\n". | 346 assert_call_depth--; |
221 str = disp (expected); | |
222 idx = find (str != "\n"); | |
223 if (! isempty (idx)) | |
224 str = str(idx(1):idx(end)); | |
225 endif | |
226 str2 = disp (cond); | |
227 idx = find (str2 != "\n"); | |
228 if (! isempty (idx)) | |
229 str2 = str2 (idx(1):idx(end)); | |
230 endif | |
231 msg = ["assert " in " expected\n" str "\nbut got\n" str2]; | |
232 if (! isempty (coda)) | |
233 msg = [msg, "\n", coda]; | |
234 endif | |
235 error ("%s", msg); | |
236 endif | 347 endif |
237 | 348 |
238 endfunction | 349 endfunction |
239 | 350 |
240 | 351 |
266 %!error assert (3, 3+2*eps, eps) | 377 %!error assert (3, 3+2*eps, eps) |
267 | 378 |
268 ## vectors | 379 ## vectors |
269 %!assert ([1,2,3],[1,2,3]); | 380 %!assert ([1,2,3],[1,2,3]); |
270 %!assert ([1;2;3],[1;2;3]); | 381 %!assert ([1;2;3],[1;2;3]); |
271 %!error assert ([2;2;3],[1;2;3]); | 382 %!error assert ([2,2,3,3],[1,2,3,4]); |
383 %!error assert ([6;6;7;7],[5;6;7;8]); | |
272 %!error assert ([1,2,3],[1;2;3]); | 384 %!error assert ([1,2,3],[1;2;3]); |
273 %!error assert ([1,2],[1,2,3]); | 385 %!error assert ([1,2],[1,2,3]); |
274 %!error assert ([1;2;3],[1;2]); | 386 %!error assert ([1;2;3],[1;2]); |
275 %!assert ([1,2;3,4],[1,2;3,4]); | 387 %!assert ([1,2;3,4],[1,2;3,4]); |
276 %!error assert ([1,4;3,4],[1,2;3,4]) | 388 %!error assert ([1,4;3,4],[1,2;3,4]) |
277 %!error assert ([1,3;2,4;3,5],[1,2;3,4]) | 389 %!error assert ([1,3;2,4;3,5],[1,2;3,4]) |
390 | |
391 ## matrices | |
392 %!test | |
393 %! A = [1 2 3]'*[1,2]; | |
394 %! assert (A,A); | |
395 %! fail ("assert (A.*(A!=2),A)"); | |
396 %! X = zeros (2,2,3); | |
397 %! Y = X; | |
398 %! Y (1,2,3) = 1; | |
399 %! fail ("assert (X,Y)"); | |
278 | 400 |
279 ## must give a small tolerance for floating point errors on relative | 401 ## must give a small tolerance for floating point errors on relative |
280 %!assert (100+100*eps, 100, -2*eps) | 402 %!assert (100+100*eps, 100, -2*eps) |
281 %!assert (100, 100+100*eps, -2*eps) | 403 %!assert (100, 100+100*eps, -2*eps) |
282 %!error assert (100+300*eps, 100, -2*eps) | 404 %!error assert (100+300*eps, 100, -2*eps) |
291 %!error assert (100+100*eps, 100, 2*eps); # fail absolute | 413 %!error assert (100+100*eps, 100, 2*eps); # fail absolute |
292 | 414 |
293 ## exceptional values | 415 ## exceptional values |
294 %!assert ([NaN, NA, Inf, -Inf, 1+eps, eps], [NaN, NA, Inf, -Inf, 1, 0], eps) | 416 %!assert ([NaN, NA, Inf, -Inf, 1+eps, eps], [NaN, NA, Inf, -Inf, 1, 0], eps) |
295 %!error assert (NaN, 1) | 417 %!error assert (NaN, 1) |
418 %!error assert ([NaN 1], [1 NaN]) | |
296 %!error assert (NA, 1) | 419 %!error assert (NA, 1) |
420 %!error assert ([NA 1]', [1 NA]') | |
421 %!error assert ([(complex (NA, 1)) (complex (2, NA))], [(complex (NA, 2)) 2]) | |
297 %!error assert (-Inf, Inf) | 422 %!error assert (-Inf, Inf) |
423 %!error assert ([-Inf Inf], [Inf -Inf]) | |
424 %!error assert (complex (Inf, 0.2), complex (-Inf, 0.2 + 2*eps), eps) | |
298 | 425 |
299 ## strings | 426 ## strings |
300 %!assert ("dog", "dog") | 427 %!assert ("dog", "dog") |
301 %!error assert ("dog", "cat") | 428 %!error assert ("dog", "cat") |
302 %!error assert ("dog", 3) | 429 %!error assert ("dog", 3) |
303 %!error assert (3, "dog") | 430 %!error assert (3, "dog") |
431 %!error assert (cellstr ("dog"), "dog") | |
432 %!error assert (cell2struct ({"dog"; 3}, {"pet", "age"}, 1), "dog"); | |
304 | 433 |
305 ## structures | 434 ## structures |
306 %!shared x,y | 435 %!shared x,y |
307 %! x.a = 1; x.b=[2, 2]; | 436 %! x.a = 1; x.b=[2, 2]; |
308 %! y.a = 1; y.b=[2, 2]; | 437 %! y.a = 1; y.b=[2, 2]; |
328 %! fail ("assert (x, y)"); | 457 %! fail ("assert (x, y)"); |
329 %! y = x; y(2,1) = 101; | 458 %! y = x; y(2,1) = 101; |
330 %! fail ("assert (x, y)"); | 459 %! fail ("assert (x, y)"); |
331 %! y = x; y(2,2) = "cat"; | 460 %! y = x; y(2,2) = "cat"; |
332 %! fail ("assert (x, y)"); | 461 %! fail ("assert (x, y)"); |
333 | 462 %! y = x; y(1,1) = [2]; y(1,2) = [0, 2, 3]; y(2,1) = 101; y(2,2) = "cat"; |
334 %% Test input validation | 463 %! fail ("assert (x, y)"); |
464 | |
465 ## variable tolerance | |
466 %!test | |
467 %! x = [-40:0]; | |
468 %! y1 = (10.^x).*(10.^x); | |
469 %! y2 = 10.^(2*x); | |
470 %! assert (y1, y2, eps (y1)); | |
471 %! fail ("assert (y1, y2 + eps*1e-70, eps (y1))"); | |
472 | |
473 ## test input validation | |
335 %!error assert | 474 %!error assert |
336 %!error assert (1,2,3,4) | 475 %!error assert (1,2,3,4) |
337 | 476 |
477 | |
478 ## Convert all indeces into tuple format | |
479 function cout = construct_indeces (matsize, erridx) | |
480 | |
481 cout = cell (numel (erridx), 1); | |
482 tmp = cell (1, numel (matsize)); | |
483 [tmp{:}] = ind2sub (matsize, erridx (:)); | |
484 subs = [tmp{:}]; | |
485 if (numel (matsize) == 2) | |
486 subs = subs (:, matsize != 1); | |
487 endif | |
488 for i = 1:numel (erridx) | |
489 loc = sprintf ("%d,", subs(i,:)); | |
490 cout{i} = ["(" loc(1:end-1) ")"]; | |
491 endfor | |
492 | |
493 endfunction | |
494 | |
495 | |
496 ## Pretty print the various errors in a condensed tabular format. | |
497 function str = pprint (in, err) | |
498 | |
499 str = sprintf (cstrcat ("ASSERT errors for: assert ", in, "\n")); | |
500 str = cstrcat (str, sprintf ("\n Location | Observed | Expected | Reason\n")); | |
501 prespace = zeros (3); | |
502 postspace = zeros (3); | |
503 for i = 1:length (err.index) | |
504 len = length (err.index{i}); | |
505 prespace (1) = floor ((10 - len) / 2); | |
506 postspace (1) = 10 - len - prespace (1); | |
507 len = length (err.observed{i}); | |
508 prespace (2) = floor ((10 - len) / 2); | |
509 postspace (2) = 10 - len - prespace (2); | |
510 len = length (err.expected{i}); | |
511 prespace (3) = floor ((10 - len) / 2); | |
512 postspace (3) = 10 - len - prespace (3); | |
513 str = cstrcat (str, sprintf ("%s %s %s %s %s %s %s %s %s %s\n", ... | |
514 repmat (' ', 1, prespace (1)), ... | |
515 err.index{i}, ... | |
516 repmat (' ', 1, postspace (1)), ... | |
517 repmat (' ', 1, prespace (2)), ... | |
518 err.observed{i}, ... | |
519 repmat (' ', 1, postspace (2)), ... | |
520 repmat (' ', 1, prespace (3)), ... | |
521 err.expected{i}, ... | |
522 repmat (' ', 1, postspace (3)), ... | |
523 err.reason{i})); | |
524 endfor | |
525 | |
526 endfunction |