comparison scripts/testfun/assert.m @ 17255:a28c0d73e253

assert.m: Added many more %!tests for function. Fixed multiple bugs discovered. * scripts/testfun/assert.m: Adjust call_depth at every exit point of function to fix recursion errors. Fix incorrectly reported errors with row vector input. Add new reason text "expected XXX, but observed YYY" where XXX is "cell" or "struct". Stop reporting multiple errors when condition is both an exceptional value and not meeting tolerance. Improve %!tests to actually catch assert failing in the correct way, rather than just failing.
author Rik <rik@octave.org>
date Thu, 15 Aug 2013 12:27:37 -0700
parents e3870f594d8b
children 09543e9c8f40
comparison
equal deleted inserted replaced
17254:7fb4461997aa 17255:a28c0d73e253
75 endfor 75 endfor
76 in = ["(" in ")"]; 76 in = ["(" in ")"];
77 77
78 if (nargin == 1 || (nargin > 1 && islogical (cond) && ischar (varargin{1}))) 78 if (nargin == 1 || (nargin > 1 && islogical (cond) && ischar (varargin{1})))
79 if ((! isnumeric (cond) && ! islogical (cond)) || ! all (cond(:))) 79 if ((! isnumeric (cond) && ! islogical (cond)) || ! all (cond(:)))
80 call_depth--;
80 if (nargin == 1) 81 if (nargin == 1)
81 ## Perhaps, say which elements failed? 82 ## Perhaps, say which elements failed?
82 error ("assert %s failed", in); 83 error ("assert %s failed", in);
83 else 84 else
84 error (varargin{:}); 85 error (varargin{:});
98 err.expected = {}; 99 err.expected = {};
99 err.reason = {}; 100 err.reason = {};
100 101
101 if (ischar (expected)) 102 if (ischar (expected))
102 if (! ischar (cond)) 103 if (! ischar (cond))
103 err.index{end+1} = "[]"; 104 err.index{end+1} = ".";
104 err.expected{end+1} = expected; 105 err.expected{end+1} = expected;
105 if (isnumeric (cond)) 106 if (isnumeric (cond))
106 err.observed{end+1} = num2str (cond); 107 err.observed{end+1} = num2str (cond);
107 err.reason{end+1} = "Expected string, but observed number"; 108 err.reason{end+1} = "Expected string, but observed number";
108 elseif (iscell (cond))
109 err.observed{end+1} = "{}";
110 err.reason{end+1} = "Expected string, but observed cell";
111 else 109 else
112 err.observed{end+1} = "[]"; 110 err.observed{end+1} = "O";
113 err.reason{end+1} = "Expected string, but observed struct"; 111 err.reason{end+1} = ["Expected string, but observed " class(cond)];
114 end 112 endif
115 elseif (! strcmp (cond, expected)) 113 elseif (! strcmp (cond, expected))
116 err.index{end+1} = "[]"; 114 err.index{end+1} = "[]";
117 err.observed{end+1} = cond; 115 err.observed{end+1} = cond;
118 err.expected{end+1} = expected; 116 err.expected{end+1} = expected;
119 err.reason{end+1} = "Strings don't match"; 117 err.reason{end+1} = "Strings don't match";
120 endif 118 endif
121 119
122 elseif (iscell (expected)) 120 elseif (iscell (expected))
123 if (! iscell (cond) || any (size (cond) != size (expected))) 121 if (! iscell (cond))
124 err.index{end+1} = "{}"; 122 err.index{end+1} = ".";
125 err.observed{end+1} = "O"; 123 err.observed{end+1} = "O";
126 err.expected{end+1} = "E"; 124 err.expected{end+1} = "E";
127 err.reason{end+1} = "Cell sizes don't match"; 125 err.reason{end+1} = ["Expected cell, but observed " class(cond)];
126 elseif (ndims (cond) != ndims (expected)
127 || any (size (cond) != size (expected)))
128 err.index{end+1} = ".";
129 err.observed{end+1} = ["O(" sprintf("%dx", size(cond))(1:end-1) ")"];
130 err.expected{end+1} = ["E(" sprintf("%dx", size(expected))(1:end-1) ")"];
131 err.reason{end+1} = "Dimensions don't match";
128 else 132 else
129 try 133 try
130 ## Recursively compare cell arrays 134 ## Recursively compare cell arrays
131 for i = 1:length (expected(:)) 135 for i = 1:length (expected(:))
132 assert (cond{i}, expected{i}, tol); 136 assert (cond{i}, expected{i}, tol);
138 err.reason{end+1} = "Cell configuration error"; 142 err.reason{end+1} = "Cell configuration error";
139 end_try_catch 143 end_try_catch
140 endif 144 endif
141 145
142 elseif (isstruct (expected)) 146 elseif (isstruct (expected))
143 if (! isstruct (cond) || any (size (cond) != size (expected)) 147 if (! isstruct (cond))
144 || rows (fieldnames (cond)) != rows (fieldnames (expected))) 148 err.index{end+1} = ".";
145 err.index{end+1} = "{}";
146 err.observed{end+1} = "O"; 149 err.observed{end+1} = "O";
147 err.expected{end+1} = "E"; 150 err.expected{end+1} = "E";
151 err.reason{end+1} = ["Expected struct, but observed " class(cond)];
152 elseif (ndims (cond) != ndims (expected)
153 || any (size (cond) != size (expected))
154 || rows (fieldnames (cond)) != rows (fieldnames (expected)))
155
156 err.index{end+1} = ".";
157 err.observed{end+1} = ["O(" sprintf("%dx", size(cond))(1:end-1) ")"];
158 err.expected{end+1} = ["E(" sprintf("%dx", size(expected))(1:end-1) ")"];
148 err.reason{end+1} = "Structure sizes don't match"; 159 err.reason{end+1} = "Structure sizes don't match";
149 else 160 else
150 try 161 try
151 empty = isempty (cond); 162 empty = isempty (cond);
152 normal = (numel (cond) == 1); 163 normal = (numel (cond) == 1);
217 228
218 A = cond; 229 A = cond;
219 B = expected; 230 B = expected;
220 231
221 ## Check exceptional values. 232 ## Check exceptional values.
222 erridx = find ( isna (real (A)) != isna (real (B)) 233 errvec = ( isna (real (A)) != isna (real (B))
223 | isna (imag (A)) != isna (imag (B))); 234 | isna (imag (A)) != isna (imag (B)));
235 erridx = find (errvec);
224 if (! isempty (erridx)) 236 if (! isempty (erridx))
225 err.index(end+1:end + length (erridx)) = ... 237 err.index(end+1:end+length (erridx)) = ...
226 ind2tuple (size (A), erridx); 238 ind2tuple (size (A), erridx);
227 err.observed(end+1:end + length (erridx)) = ... 239 err.observed(end+1:end+length (erridx)) = ...
228 strtrim (cellstr (num2str (A(erridx) (:)))); 240 strtrim (cellstr (num2str (A(erridx) (:))));
229 err.expected(end+1:end + length (erridx)) = ... 241 err.expected(end+1:end+length (erridx)) = ...
230 strtrim (cellstr (num2str (B(erridx) (:)))); 242 strtrim (cellstr (num2str (B(erridx) (:))));
231 err.reason(end+1:end + length (erridx)) = ... 243 err.reason(end+1:end+length (erridx)) = ...
232 cellstr (repmat ("'NA' mismatch", length (erridx), 1)); 244 repmat ({"'NA' mismatch"}, length (erridx), 1);
233 endif 245 endif
234 246 errseen = errvec;
235 erridx = find ( isnan (real (A)) != isnan (real (B)) 247
236 | isnan (imag (A)) != isnan (imag (B))); 248 errvec = ( isnan (real (A)) != isnan (real (B))
249 | isnan (imag (A)) != isnan (imag (B)));
250 erridx = find (errvec & !errseen);
237 if (! isempty (erridx)) 251 if (! isempty (erridx))
238 err.index(end+1:end + length (erridx)) = ... 252 err.index(end+1:end+length (erridx)) = ...
239 ind2tuple (size (A), erridx); 253 ind2tuple (size (A), erridx);
240 err.observed(end+1:end + length (erridx)) = ... 254 err.observed(end+1:end+length (erridx)) = ...
241 strtrim (cellstr (num2str (A(erridx) (:)))); 255 strtrim (cellstr (num2str (A(erridx) (:))));
242 err.expected(end+1:end + length (erridx)) = ... 256 err.expected(end+1:end+length (erridx)) = ...
243 strtrim (cellstr (num2str (B(erridx) (:)))); 257 strtrim (cellstr (num2str (B(erridx) (:))));
244 err.reason(end+1:end + length (erridx)) = ... 258 err.reason(end+1:end+length (erridx)) = ...
245 cellstr (repmat ("'NaN' mismatch", length (erridx), 1)); 259 repmat ({"'NaN' mismatch"}, length (erridx), 1);
246 endif 260 endif
247 261 errseen |= errvec;
248 erridx = find (((isinf (real (A)) | isinf (real (B))) ... 262
249 & real (A) != real (B)) ... 263 errvec = ((isinf (real (A)) | isinf (real (B))) ...
250 | ((isinf (imag (A)) | isinf (imag (B))) 264 & (real (A) != real (B))) ...
251 & imag (A) != imag (B))); 265 | ((isinf (imag (A)) | isinf (imag (B))) ...
266 & (imag (A) != imag (B)));
267 erridx = find (errvec & !errseen);
252 if (! isempty (erridx)) 268 if (! isempty (erridx))
253 err.index(end+1:end + length (erridx)) = ... 269 err.index(end+1:end+length (erridx)) = ...
254 ind2tuple (size (A), erridx); 270 ind2tuple (size (A), erridx);
255 err.observed(end+1:end + length (erridx)) = ... 271 err.observed(end+1:end+length (erridx)) = ...
256 strtrim (cellstr (num2str (A(erridx) (:)))); 272 strtrim (cellstr (num2str (A(erridx) (:))));
257 err.expected(end+1:end + length (erridx)) = ... 273 err.expected(end+1:end+length (erridx)) = ...
258 strtrim (cellstr (num2str (B(erridx) (:)))); 274 strtrim (cellstr (num2str (B(erridx) (:))));
259 err.reason(end+1:end + length (erridx)) = ... 275 err.reason(end+1:end+length (erridx)) = ...
260 cellstr (repmat ("'Inf' mismatch", length (erridx), 1)); 276 repmat ({"'Inf' mismatch"}, length (erridx), 1);
261 endif 277 endif
278 errseen |= errvec;
262 279
263 ## Check normal values. 280 ## Check normal values.
264 ## Replace exceptional values already checked above by zero. 281 ## Replace exceptional values already checked above by zero.
265 A_null_real = real (A); 282 A_null_real = real (A);
266 B_null_real = real (B); 283 B_null_real = real (B);
267 exclude = ! isfinite (A_null_real) & ! isfinite (B_null_real); 284 exclude = errseen | ! isfinite (A_null_real) & ! isfinite (B_null_real);
268 A_null_real(exclude) = 0; 285 A_null_real(exclude) = 0;
269 B_null_real(exclude) = 0; 286 B_null_real(exclude) = 0;
270 A_null_imag = imag (A); 287 A_null_imag = imag (A);
271 B_null_imag = imag (B); 288 B_null_imag = imag (B);
272 exclude = ! isfinite (A_null_imag) & ! isfinite (B_null_imag); 289 exclude = errseen | ! isfinite (A_null_imag) & ! isfinite (B_null_imag);
273 A_null_imag(exclude) = 0; 290 A_null_imag(exclude) = 0;
274 B_null_imag(exclude) = 0; 291 B_null_imag(exclude) = 0;
275 A_null = complex (A_null_real, A_null_imag); 292 A_null = complex (A_null_real, A_null_imag);
276 B_null = complex (B_null_real, B_null_imag); 293 B_null = complex (B_null_real, B_null_imag);
277 if (isscalar (tol)) 294 if (isscalar (tol))
281 endif 298 endif
282 299
283 k = (mtol == 0); 300 k = (mtol == 0);
284 erridx = find ((A_null != B_null) & k); 301 erridx = find ((A_null != B_null) & k);
285 if (! isempty (erridx)) 302 if (! isempty (erridx))
286 err.index(end+1:end + length (erridx)) = ... 303 err.index(end+1:end+length (erridx)) = ...
287 ind2tuple (size (A), erridx); 304 ind2tuple (size (A), erridx);
288 err.observed(end+1:end + length (erridx)) = ... 305 err.observed(end+1:end+length (erridx)) = ...
289 strtrim (cellstr (num2str (A(erridx) (:)))); 306 strtrim (cellstr (num2str (A(erridx) (:))));
290 err.expected(end+1:end + length (erridx)) = ... 307 err.expected(end+1:end+length (erridx)) = ...
291 strtrim (cellstr (num2str (B(erridx) (:)))); 308 strtrim (cellstr (num2str (B(erridx) (:))));
292 err.reason(end+1:end + length (erridx)) = ... 309 err.reason(end+1:end+length (erridx)) = ...
293 ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... 310 ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n",...
294 [abs(A_null(erridx) - B_null(erridx)) mtol(erridx)]')), "\n"); 311 [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n");
295 endif 312 endif
296 313
297 k = (mtol > 0); 314 k = (mtol > 0);
298 erridx = find ((abs (A_null - B_null) > mtol) & k); 315 erridx = find ((abs (A_null - B_null) > mtol) & k);
299 if (! isempty (erridx)) 316 if (! isempty (erridx))
300 err.index(end+1:end + length (erridx)) = ... 317 err.index(end+1:end+length (erridx)) = ...
301 ind2tuple (size (A), erridx); 318 ind2tuple (size (A), erridx);
302 err.observed(end+1:end + length (erridx)) = ... 319 err.observed(end+1:end+length (erridx)) = ...
303 strtrim (cellstr (num2str (A(erridx) (:)))); 320 strtrim (cellstr (num2str (A(erridx) (:))));
304 err.expected(end+1:end + length (erridx)) = ... 321 err.expected(end+1:end+length (erridx)) = ...
305 strtrim (cellstr (num2str (B(erridx) (:)))); 322 strtrim (cellstr (num2str (B(erridx) (:))));
306 err.reason(end+1:end + length (erridx)) = ... 323 err.reason(end+1:end+length (erridx)) = ...
307 ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... 324 ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n",...
308 [abs(A_null(erridx) - B_null(erridx)) mtol(erridx)]')), "\n"); 325 [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n");
309 endif 326 endif
310 327
311 k = (mtol < 0); 328 k = (mtol < 0);
312 if (any (k)) 329 if (any (k(:)))
313 ## Test for absolute error where relative error can't be calculated. 330 ## Test for absolute error where relative error can't be calculated.
314 erridx = find ((B_null == 0) & abs (A_null) > abs (mtol) & k); 331 erridx = find ((B_null == 0) & abs (A_null) > abs (mtol) & k);
315 if (! isempty (erridx)) 332 if (! isempty (erridx))
316 err.index(end+1:end + length (erridx)) = ... 333 err.index(end+1:end+length (erridx)) = ...
317 ind2tuple (size (A), erridx); 334 ind2tuple (size (A), erridx);
318 err.observed(end+1:end + length (erridx)) = ... 335 err.observed(end+1:end+length (erridx)) = ...
319 strtrim (cellstr (num2str (A(erridx) (:)))); 336 strtrim (cellstr (num2str (A(erridx) (:))));
320 err.expected(end+1:end + length (erridx)) = ... 337 err.expected(end+1:end+length (erridx)) = ...
321 strtrim (cellstr (num2str (B(erridx) (:)))); 338 strtrim (cellstr (num2str (B(erridx) (:))));
322 err.reason(end+1:end + length (erridx)) = ... 339 err.reason(end+1:end+length (erridx)) = ...
323 ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", 340 ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n",
324 [abs(A_null(erridx) - B_null(erridx)) -mtol(erridx)]')), "\n"); 341 [abs(A_null(erridx) - B_null(erridx)) -mtol(erridx)]')), "\n");
325 endif 342 endif
326 ## Test for relative error 343 ## Test for relative error
327 Bdiv = Inf (size (B_null)); 344 Bdiv = Inf (size (B_null));
328 Bdiv(k & (B_null != 0)) = B_null(k & (B_null != 0)); 345 Bdiv(k & (B_null != 0)) = B_null(k & (B_null != 0));
329 relerr = abs ((A_null - B_null) ./ abs (Bdiv)); 346 relerr = abs ((A_null - B_null) ./ abs (Bdiv));
330 erridx = find ((relerr > abs (mtol)) & k); 347 erridx = find ((relerr > abs (mtol)) & k);
331 if (! isempty (erridx)) 348 if (! isempty (erridx))
332 err.index(end+1:end + length (erridx)) = ... 349 err.index(end+1:end+length (erridx)) = ...
333 ind2tuple (size (A), erridx); 350 ind2tuple (size (A), erridx);
334 err.observed(end+1:end + length (erridx)) = ... 351 err.observed(end+1:end+length (erridx)) = ...
335 strtrim (cellstr (num2str (A(erridx) (:)))); 352 strtrim (cellstr (num2str (A(erridx) (:))));
336 err.expected(end+1:end + length (erridx)) = ... 353 err.expected(end+1:end+length (erridx)) = ...
337 strtrim (cellstr (num2str (B(erridx) (:)))); 354 strtrim (cellstr (num2str (B(erridx) (:))));
338 err.reason(end+1:end + length (erridx)) = ... 355 err.reason(end+1:end+length (erridx)) = ...
339 ostrsplit (deblank (sprintf ("Rel err %g exceeds tol %g\n", 356 ostrsplit (deblank (sprintf ("Rel err %.5g exceeds tol %.5g\n",
340 [relerr(erridx) -mtol(erridx)]')), "\n"); 357 [relerr(erridx)(:) -mtol(erridx)(:)]')), "\n");
341 endif 358 endif
342 endif 359 endif
343 endif 360 endif
344 361
345 endif 362 endif
367 384
368 385
369 ## empty input 386 ## empty input
370 %!assert ([]) 387 %!assert ([])
371 %!assert (zeros (3,0), zeros (3,0)) 388 %!assert (zeros (3,0), zeros (3,0))
372 %!error assert (zeros (3,0), zeros (0,2)) 389 %!error <O\(3x0\)\s+E\(0x2\)> assert (zeros (3,0), zeros (0,2))
373 %!error assert (zeros (3,0), []) 390 %!error <Dimensions don't match> assert (zeros (3,0), [])
374 %!error <Dimensions don't match> assert (zeros (2,0,2), zeros (2,0)) 391 %!error <Dimensions don't match> assert (zeros (2,0,2), zeros (2,0))
375 392
376 ## conditions 393 ## conditions
377 %!assert (isempty ([])) 394 %!assert (isempty ([]))
378 %!assert (1) 395 %!assert (1)
383 %!error assert ([1,0,1]) 400 %!error assert ([1,0,1])
384 %!error assert ([1;1;0]) 401 %!error assert ([1;1;0])
385 %!error assert ([1,0;1,1]) 402 %!error assert ([1,0;1,1])
386 403
387 ## scalars 404 ## scalars
388 %!error assert (3, [3,3; 3,3]) 405 %!error <Dimensions don't match> assert (3, [3,3])
389 %!error assert ([3,3; 3,3], 3) 406 %!error <Dimensions don't match> assert (3, [3,3; 3,3])
407 %!error <Dimensions don't match> assert ([3,3; 3,3], 3)
390 %!assert (3, 3) 408 %!assert (3, 3)
409 %!error <Abs err 1 exceeds tol> assert (3, 4)
391 %!assert (3+eps, 3, eps) 410 %!assert (3+eps, 3, eps)
392 %!assert (3, 3+eps, eps) 411 %!assert (3, 3+eps, eps)
393 %!error assert (3+2*eps, 3, eps) 412 %!error <Abs err 4.4409e-16 exceeds tol> assert (3+2*eps, 3, eps)
394 %!error assert (3, 3+2*eps, eps) 413 %!error <Abs err 4.4409e-16 exceeds tol> assert (3, 3+2*eps, eps)
395 414
396 ## vectors 415 ## vectors
397 %!assert ([1,2,3],[1,2,3]); 416 %!assert ([1,2,3],[1,2,3]);
398 %!assert ([1;2;3],[1;2;3]); 417 %!assert ([1;2;3],[1;2;3]);
399 %!error assert ([2,2,3,3],[1,2,3,4]); 418 %!error <Abs err 1 exceeds tol 0> assert ([2,2,3,3],[1,2,3,4]);
400 %!error assert ([6;6;7;7],[5;6;7;8]); 419 %!error <Abs err 1 exceeds tol 0.5> assert ([2,2,3,3],[1,2,3,4],0.5);
401 %!error assert ([1,2,3],[1;2;3]); 420 %!error <Rel err 1 exceeds tol 0.1> assert ([2,2,3,5],[1,2,3,4],-0.1);
402 %!error assert ([1,2],[1,2,3]); 421 %!error <Abs err 1 exceeds tol 0> assert ([6;6;7;7],[5;6;7;8]);
403 %!error assert ([1;2;3],[1;2]); 422 %!error <Abs err 1 exceeds tol 0.5> assert ([6;6;7;7],[5;6;7;8],0.5);
423 %!error <Rel err .* exceeds tol 0.1> assert ([6;6;7;7],[5;6;7;8],-0.1);
424 %!error <Dimensions don't match> assert ([1,2,3],[1;2;3]);
425 %!error <Dimensions don't match> assert ([1,2],[1,2,3]);
426 %!error <Dimensions don't match> assert ([1;2;3],[1;2]);
427
428 ## matrices
404 %!assert ([1,2;3,4],[1,2;3,4]); 429 %!assert ([1,2;3,4],[1,2;3,4]);
405 %!error assert ([1,4;3,4],[1,2;3,4]) 430 %!error <\(1,2\)\s+4\s+2> assert ([1,4;3,4],[1,2;3,4])
406 %!error assert ([1,3;2,4;3,5],[1,2;3,4]) 431 %!error <Dimensions don't match> assert ([1,3;2,4;3,5],[1,2;3,4])
407 432 %!test # 2-D matrix
408 ## matrices
409 %!test
410 %! A = [1 2 3]'*[1,2]; 433 %! A = [1 2 3]'*[1,2];
411 %! assert (A,A); 434 %! assert (A, A);
412 %! fail ("assert (A.*(A!=2),A)"); 435 %! fail ("assert (A.*(A!=2),A)");
436 %!test # N-D matrix
413 %! X = zeros (2,2,3); 437 %! X = zeros (2,2,3);
414 %! Y = X; 438 %! Y = X;
415 %! Y (1,2,3) = 1; 439 %! Y(1,2,3) = 1.5;
416 %! fail ("assert (X,Y)"); 440 %! fail ("assert (X,Y)", "\(1,2,3\).*Abs err 1.5 exceeds tol 0");
417 441
418 ## must give a small tolerance for floating point errors on relative 442 ## must give a small tolerance for floating point errors on relative
419 %!assert (100+100*eps, 100, -2*eps) 443 %!assert (100+100*eps, 100, -2*eps)
420 %!assert (100, 100+100*eps, -2*eps) 444 %!assert (100, 100+100*eps, -2*eps)
421 %!error assert (100+300*eps, 100, -2*eps) 445 %!error <Rel err .* exceeds tol> assert (100+300*eps, 100, -2*eps)
422 %!error assert (100, 100+300*eps, -2*eps) 446 %!error <Rel err .* exceeds tol> assert (100, 100+300*eps, -2*eps)
423 %!error assert (3, [3,3])
424 %!error assert (3, 4)
425 447
426 ## test relative vs. absolute tolerances 448 ## test relative vs. absolute tolerances
427 %!test assert (0.1+eps, 0.1, 2*eps); # accept absolute 449 %!test assert (0.1+eps, 0.1, 2*eps);
428 %!error assert (0.1+eps, 0.1, -2*eps); # fail relative 450 %!error <Rel err 2.2204e-15 exceeds tol> assert (0.1+eps, 0.1, -2*eps);
429 %!test assert (100+100*eps, 100, -2*eps); # accept relative 451 %!test assert (100+100*eps, 100, -2*eps);
430 %!error assert (100+100*eps, 100, 2*eps); # fail absolute 452 %!error <Abs err 2.8422e-14 exceeds tol> assert (100+100*eps, 100, 2*eps);
453
454 ## Corner case of relative tolerance with 0 divider
455 %!error <Abs err 2 exceeds tol 0.1> assert (2, 0, -0.1)
456
457 ## Extra checking of inputs when tolerance unspecified.
458 %!error <Class single != double> assert (single (1), 1)
459 %!error <Class uint8 != uint16> assert (uint8 (1), uint16 (1))
460 %!error <sparse != non-sparse> assert (sparse([1]), [1])
461 %!error <non-sparse != sparse> assert ([1], sparse([1]))
462 %!error <complex != real> assert (1+i, 1)
463 %!error <real != complex> assert (1, 1+i)
431 464
432 ## exceptional values 465 ## exceptional values
433 %!assert ([NaN, NA, Inf, -Inf, 1+eps, eps], [NaN, NA, Inf, -Inf, 1, 0], eps) 466 %!assert ([NaN, NA, Inf, -Inf, 1+eps, eps], [NaN, NA, Inf, -Inf, 1, 0], eps)
434 %!error assert (NaN, 1) 467
435 %!error assert ([NaN 1], [1 NaN]) 468 %!error <'NaN' mismatch> assert (NaN, 1)
436 %!error assert (NA, 1) 469 %!error <'NaN' mismatch> assert ([NaN 1], [1 NaN])
470 %!test
471 %! try
472 %! assert ([NaN 1], [1 NaN]);
473 %! catch
474 %! errmsg = lasterr ();
475 %! if (sum (errmsg () == "\n") != 4)
476 %! error ("Too many errors reported for NaN assert");
477 %! elseif (strfind (errmsg, "NA"))
478 %! error ("NA reported for NaN assert");
479 %! elseif (strfind (errmsg, "Abs err NaN exceeds tol 0"))
480 %! error ("Abs err reported for NaN assert");
481 %! endif
482 %! end_try_catch
483
484 %!error <'NA' mismatch> assert (NA, 1)
437 %!error assert ([NA 1]', [1 NA]') 485 %!error assert ([NA 1]', [1 NA]')
486 %!test
487 %! try
488 %! assert ([NA 1]', [1 NA]');
489 %! catch
490 %! errmsg = lasterr ();
491 %! if (sum (errmsg () == "\n") != 4)
492 %! error ("Too many errors reported for NA assert");
493 %! elseif (strfind (errmsg, "NaN"))
494 %! error ("NaN reported for NA assert");
495 %! elseif (strfind (errmsg, "Abs err NA exceeds tol 0"))
496 %! error ("Abs err reported for NA assert");
497 %! endif
498 %! end_try_catch
438 %!error assert ([(complex (NA, 1)) (complex (2, NA))], [(complex (NA, 2)) 2]) 499 %!error assert ([(complex (NA, 1)) (complex (2, NA))], [(complex (NA, 2)) 2])
439 %!error assert (-Inf, Inf) 500
440 %!error assert ([-Inf Inf], [Inf -Inf]) 501 %!error <'Inf' mismatch> assert (-Inf, Inf)
441 %!error assert (complex (Inf, 0.2), complex (-Inf, 0.2 + 2*eps), eps) 502 %!error <'Inf' mismatch> assert ([-Inf Inf], [Inf -Inf])
503 %!test
504 %! try
505 %! assert (complex (Inf, 0.2), complex (-Inf, 0.2 + 2*eps), eps);
506 %! catch
507 %! errmsg = lasterr ();
508 %! if (sum (errmsg () == "\n") != 3)
509 %! error ("Too many errors reported for Inf assert");
510 %! elseif (strfind (errmsg, "Abs err"))
511 %! error ("Abs err reported for Inf assert");
512 %! endif
513 %! end_try_catch
514 %!error <Abs err> assert (complex (Inf, 0.2), complex (Inf, 0.2 + 2*eps), eps)
442 515
443 ## strings 516 ## strings
444 %!assert ("dog", "dog") 517 %!assert ("dog", "dog")
445 %!error assert ("dog", "cat") 518 %!error <Strings don't match> assert ("dog", "cat")
446 %!error assert ("dog", 3) 519 %!error <Expected string, but observed number> assert (3, "dog")
447 %!error assert (3, "dog") 520 %!error <Class char != double> assert ("dog", [3 3 3])
448 %!error assert (cellstr ("dog"), "dog") 521 %!error <Expected string, but observed cell> assert ({"dog"}, "dog")
449 %!error assert (cell2struct ({"dog"; 3}, {"pet", "age"}, 1), "dog"); 522 %!error <Expected string, but observed struct> assert (struct ("dog", 3), "dog")
450
451 ## structures
452 %!shared x,y
453 %! x.a = 1; x.b=[2, 2];
454 %! y.a = 1; y.b=[2, 2];
455 %!assert (x, y)
456 %!test y.b=3;
457 %!error assert (x, y)
458 %!error assert (3, x)
459 %!error assert (x, 3)
460 %!test
461 %! # Empty structures
462 %! x = resize (x, 0, 1);
463 %! y = resize (y, 0, 1);
464 %! assert (x, y);
465 523
466 ## cell arrays 524 ## cell arrays
525 %!error <Expected cell, but observed double> assert (1, {1})
526 %!error <Dimensions don't match> assert (cell (1,2,3), cell (3,2,1))
527 %!test
528 %! x = {{{1}}, 2}; # cell with multiple levels
529 %! y = x;
530 %! assert (x,y);
531 %! y{1}{1}{1} = 3;
532 %! fail ("assert (x,y)", "Abs err 2 exceeds tol 0");
533
467 %!test 534 %!test
468 %! x = {[3], [1,2,3]; 100+100*eps, "dog"}; 535 %! x = {[3], [1,2,3]; 100+100*eps, "dog"};
469 %! y = x; 536 %! y = x;
470 %! assert (x, y); 537 %! assert (x, y);
471 %! y = x; y(1,1) = [2]; 538 %! y = x; y(1,1) = [2];
477 %! y = x; y(2,2) = "cat"; 544 %! y = x; y(2,2) = "cat";
478 %! fail ("assert (x, y)"); 545 %! fail ("assert (x, y)");
479 %! y = x; y(1,1) = [2]; y(1,2) = [0, 2, 3]; y(2,1) = 101; y(2,2) = "cat"; 546 %! y = x; y(1,1) = [2]; y(1,2) = [0, 2, 3]; y(2,1) = 101; y(2,2) = "cat";
480 %! fail ("assert (x, y)"); 547 %! fail ("assert (x, y)");
481 548
482 ## variable tolerance 549 ## structures
550 %!error <Expected struct, but observed double> assert (1, struct ("a", 1))
551 %!error <Structure sizes don't match>
552 %! x(1,2,3).a = 1;
553 %! y(1,2).a = 1;
554 %! assert (x,y);
555 %!error <Structure sizes don't match>
556 %! x(1,2,3).a = 1;
557 %! y(3,2,2).a = 1;
558 %! assert (x,y);
559 %!error <Structure sizes don't match>
560 %! x.a = 1; x.b = 1;
561 %! y.a = 1;
562 %! assert (x,y);
563 %!error <'b' is not an expected field>
564 %! x.b = 1;
565 %! y.a = 1;
566 %! assert (x,y);
567
568 %!test
569 %! x.a = 1; x.b=[2, 2];
570 %! y.a = 1; y.b=[2, 2];
571 %! assert (x, y);
572 %! y.b=3;
573 %! fail ("assert (x, y)");
574 %! fail ("assert (3, x)");
575 %! fail ("assert (x, 3)");
576 %! ## Empty structures
577 %! x = resize (x, 0, 1);
578 %! y = resize (y, 0, 1);
579 %! assert (x, y);
580
581 ## vector of tolerances
483 %!test 582 %!test
484 %! x = [-40:0]; 583 %! x = [-40:0];
485 %! y1 = (10.^x).*(10.^x); 584 %! y1 = (10.^x).*(10.^x);
486 %! y2 = 10.^(2*x); 585 %! y2 = 10.^(2*x);
487 %! assert (y1, y2, eps (y1)); 586 %! assert (y1, y2, eps (y1));
488 %! fail ("assert (y1, y2 + eps*1e-70, eps (y1))"); 587 %! fail ("assert (y1, y2 + eps*1e-70, eps (y1))");
588
589 ## Multiple tolerances
590 %!test
591 %! x = [1 2; 3 4];
592 %! y = [0 -1; 1 2];
593 %! tol = [-0.1 0; -0.2 0.3];
594 %! try
595 %! assert (x, y, tol);
596 %! catch
597 %! errmsg = lasterr ();
598 %! if (sum (errmsg () == "\n") != 6)
599 %! error ("Incorrect number of errors reported");
600 %! endif
601 %! assert (!isempty (regexp (errmsg, '\(1,2\).*Abs err 3 exceeds tol 0\>')));
602 %! assert (!isempty (regexp (errmsg, '\(2,2\).*Abs err 2 exceeds tol 0.3')));
603 %! assert (!isempty (regexp (errmsg, '\(1,1\).*Abs err 1 exceeds tol 0.1')));
604 %! assert (!isempty (regexp (errmsg, '\(2,1\).*Rel err 2 exceeds tol 0.2')));
605 %! end_try_catch
489 606
490 ## test input validation 607 ## test input validation
491 %!error assert () 608 %!error assert ()
492 %!error assert (1,2,3,4) 609 %!error assert (1,2,3,4)
493 610