Mercurial > hg > octave-lyh
diff scripts/testfun/assert.m @ 17263: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 |
line wrap: on
line diff
--- a/scripts/testfun/assert.m +++ b/scripts/testfun/assert.m @@ -77,6 +77,7 @@ if (nargin == 1 || (nargin > 1 && islogical (cond) && ischar (varargin{1}))) if ((! isnumeric (cond) && ! islogical (cond)) || ! all (cond(:))) + call_depth--; if (nargin == 1) ## Perhaps, say which elements failed? error ("assert %s failed", in); @@ -100,18 +101,15 @@ if (ischar (expected)) if (! ischar (cond)) - err.index{end+1} = "[]"; + err.index{end+1} = "."; err.expected{end+1} = expected; if (isnumeric (cond)) err.observed{end+1} = num2str (cond); err.reason{end+1} = "Expected string, but observed number"; - elseif (iscell (cond)) - err.observed{end+1} = "{}"; - err.reason{end+1} = "Expected string, but observed cell"; else - err.observed{end+1} = "[]"; - err.reason{end+1} = "Expected string, but observed struct"; - end + err.observed{end+1} = "O"; + err.reason{end+1} = ["Expected string, but observed " class(cond)]; + endif elseif (! strcmp (cond, expected)) err.index{end+1} = "[]"; err.observed{end+1} = cond; @@ -120,11 +118,17 @@ endif elseif (iscell (expected)) - if (! iscell (cond) || any (size (cond) != size (expected))) - err.index{end+1} = "{}"; + if (! iscell (cond)) + err.index{end+1} = "."; err.observed{end+1} = "O"; err.expected{end+1} = "E"; - err.reason{end+1} = "Cell sizes don't match"; + err.reason{end+1} = ["Expected cell, but observed " class(cond)]; + elseif (ndims (cond) != ndims (expected) + || any (size (cond) != size (expected))) + err.index{end+1} = "."; + err.observed{end+1} = ["O(" sprintf("%dx", size(cond))(1:end-1) ")"]; + err.expected{end+1} = ["E(" sprintf("%dx", size(expected))(1:end-1) ")"]; + err.reason{end+1} = "Dimensions don't match"; else try ## Recursively compare cell arrays @@ -140,11 +144,18 @@ endif elseif (isstruct (expected)) - if (! isstruct (cond) || any (size (cond) != size (expected)) - || rows (fieldnames (cond)) != rows (fieldnames (expected))) - err.index{end+1} = "{}"; + if (! isstruct (cond)) + err.index{end+1} = "."; err.observed{end+1} = "O"; err.expected{end+1} = "E"; + err.reason{end+1} = ["Expected struct, but observed " class(cond)]; + elseif (ndims (cond) != ndims (expected) + || any (size (cond) != size (expected)) + || rows (fieldnames (cond)) != rows (fieldnames (expected))) + + err.index{end+1} = "."; + err.observed{end+1} = ["O(" sprintf("%dx", size(cond))(1:end-1) ")"]; + err.expected{end+1} = ["E(" sprintf("%dx", size(expected))(1:end-1) ")"]; err.reason{end+1} = "Structure sizes don't match"; else try @@ -219,57 +230,63 @@ B = expected; ## Check exceptional values. - erridx = find ( isna (real (A)) != isna (real (B)) - | isna (imag (A)) != isna (imag (B))); + errvec = ( isna (real (A)) != isna (real (B)) + | isna (imag (A)) != isna (imag (B))); + erridx = find (errvec); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - cellstr (repmat ("'NA' mismatch", length (erridx), 1)); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + repmat ({"'NA' mismatch"}, length (erridx), 1); endif + errseen = errvec; - erridx = find ( isnan (real (A)) != isnan (real (B)) - | isnan (imag (A)) != isnan (imag (B))); + errvec = ( isnan (real (A)) != isnan (real (B)) + | isnan (imag (A)) != isnan (imag (B))); + erridx = find (errvec & !errseen); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - cellstr (repmat ("'NaN' mismatch", length (erridx), 1)); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + repmat ({"'NaN' mismatch"}, length (erridx), 1); endif + errseen |= errvec; - erridx = find (((isinf (real (A)) | isinf (real (B))) ... - & real (A) != real (B)) ... - | ((isinf (imag (A)) | isinf (imag (B))) - & imag (A) != imag (B))); + errvec = ((isinf (real (A)) | isinf (real (B))) ... + & (real (A) != real (B))) ... + | ((isinf (imag (A)) | isinf (imag (B))) ... + & (imag (A) != imag (B))); + erridx = find (errvec & !errseen); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - cellstr (repmat ("'Inf' mismatch", length (erridx), 1)); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + repmat ({"'Inf' mismatch"}, length (erridx), 1); endif + errseen |= errvec; ## Check normal values. ## Replace exceptional values already checked above by zero. A_null_real = real (A); B_null_real = real (B); - exclude = ! isfinite (A_null_real) & ! isfinite (B_null_real); + exclude = errseen | ! isfinite (A_null_real) & ! isfinite (B_null_real); A_null_real(exclude) = 0; B_null_real(exclude) = 0; A_null_imag = imag (A); B_null_imag = imag (B); - exclude = ! isfinite (A_null_imag) & ! isfinite (B_null_imag); + exclude = errseen | ! isfinite (A_null_imag) & ! isfinite (B_null_imag); A_null_imag(exclude) = 0; B_null_imag(exclude) = 0; A_null = complex (A_null_real, A_null_imag); @@ -283,45 +300,45 @@ k = (mtol == 0); erridx = find ((A_null != B_null) & k); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... - [abs(A_null(erridx) - B_null(erridx)) mtol(erridx)]')), "\n"); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n",... + [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n"); endif k = (mtol > 0); erridx = find ((abs (A_null - B_null) > mtol) & k); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", ... - [abs(A_null(erridx) - B_null(erridx)) mtol(erridx)]')), "\n"); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n",... + [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n"); endif k = (mtol < 0); - if (any (k)) + if (any (k(:))) ## Test for absolute error where relative error can't be calculated. erridx = find ((B_null == 0) & abs (A_null) > abs (mtol) & k); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - ostrsplit (deblank (sprintf ("Abs err %g exceeds tol %g\n", - [abs(A_null(erridx) - B_null(erridx)) -mtol(erridx)]')), "\n"); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + ostrsplit (deblank (sprintf ("Abs err %.5g exceeds tol %.5g\n", + [abs(A_null(erridx) - B_null(erridx)) -mtol(erridx)]')), "\n"); endif ## Test for relative error Bdiv = Inf (size (B_null)); @@ -329,15 +346,15 @@ relerr = abs ((A_null - B_null) ./ abs (Bdiv)); erridx = find ((relerr > abs (mtol)) & k); if (! isempty (erridx)) - err.index(end+1:end + length (erridx)) = ... - ind2tuple (size (A), erridx); - err.observed(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (A(erridx) (:)))); - err.expected(end+1:end + length (erridx)) = ... - strtrim (cellstr (num2str (B(erridx) (:)))); - err.reason(end+1:end + length (erridx)) = ... - ostrsplit (deblank (sprintf ("Rel err %g exceeds tol %g\n", - [relerr(erridx) -mtol(erridx)]')), "\n"); + err.index(end+1:end+length (erridx)) = ... + ind2tuple (size (A), erridx); + err.observed(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (A(erridx) (:)))); + err.expected(end+1:end+length (erridx)) = ... + strtrim (cellstr (num2str (B(erridx) (:)))); + err.reason(end+1:end+length (erridx)) = ... + ostrsplit (deblank (sprintf ("Rel err %.5g exceeds tol %.5g\n", + [relerr(erridx)(:) -mtol(erridx)(:)]')), "\n"); endif endif endif @@ -369,8 +386,8 @@ ## empty input %!assert ([]) %!assert (zeros (3,0), zeros (3,0)) -%!error assert (zeros (3,0), zeros (0,2)) -%!error assert (zeros (3,0), []) +%!error <O\(3x0\)\s+E\(0x2\)> assert (zeros (3,0), zeros (0,2)) +%!error <Dimensions don't match> assert (zeros (3,0), []) %!error <Dimensions don't match> assert (zeros (2,0,2), zeros (2,0)) ## conditions @@ -385,85 +402,135 @@ %!error assert ([1,0;1,1]) ## scalars -%!error assert (3, [3,3; 3,3]) -%!error assert ([3,3; 3,3], 3) +%!error <Dimensions don't match> assert (3, [3,3]) +%!error <Dimensions don't match> assert (3, [3,3; 3,3]) +%!error <Dimensions don't match> assert ([3,3; 3,3], 3) %!assert (3, 3) +%!error <Abs err 1 exceeds tol> assert (3, 4) %!assert (3+eps, 3, eps) %!assert (3, 3+eps, eps) -%!error assert (3+2*eps, 3, eps) -%!error assert (3, 3+2*eps, eps) +%!error <Abs err 4.4409e-16 exceeds tol> assert (3+2*eps, 3, eps) +%!error <Abs err 4.4409e-16 exceeds tol> assert (3, 3+2*eps, eps) ## vectors %!assert ([1,2,3],[1,2,3]); %!assert ([1;2;3],[1;2;3]); -%!error assert ([2,2,3,3],[1,2,3,4]); -%!error assert ([6;6;7;7],[5;6;7;8]); -%!error assert ([1,2,3],[1;2;3]); -%!error assert ([1,2],[1,2,3]); -%!error assert ([1;2;3],[1;2]); -%!assert ([1,2;3,4],[1,2;3,4]); -%!error assert ([1,4;3,4],[1,2;3,4]) -%!error assert ([1,3;2,4;3,5],[1,2;3,4]) +%!error <Abs err 1 exceeds tol 0> assert ([2,2,3,3],[1,2,3,4]); +%!error <Abs err 1 exceeds tol 0.5> assert ([2,2,3,3],[1,2,3,4],0.5); +%!error <Rel err 1 exceeds tol 0.1> assert ([2,2,3,5],[1,2,3,4],-0.1); +%!error <Abs err 1 exceeds tol 0> assert ([6;6;7;7],[5;6;7;8]); +%!error <Abs err 1 exceeds tol 0.5> assert ([6;6;7;7],[5;6;7;8],0.5); +%!error <Rel err .* exceeds tol 0.1> assert ([6;6;7;7],[5;6;7;8],-0.1); +%!error <Dimensions don't match> assert ([1,2,3],[1;2;3]); +%!error <Dimensions don't match> assert ([1,2],[1,2,3]); +%!error <Dimensions don't match> assert ([1;2;3],[1;2]); ## matrices -%!test +%!assert ([1,2;3,4],[1,2;3,4]); +%!error <\(1,2\)\s+4\s+2> assert ([1,4;3,4],[1,2;3,4]) +%!error <Dimensions don't match> assert ([1,3;2,4;3,5],[1,2;3,4]) +%!test # 2-D matrix %! A = [1 2 3]'*[1,2]; -%! assert (A,A); +%! assert (A, A); %! fail ("assert (A.*(A!=2),A)"); +%!test # N-D matrix %! X = zeros (2,2,3); %! Y = X; -%! Y (1,2,3) = 1; -%! fail ("assert (X,Y)"); +%! Y(1,2,3) = 1.5; +%! fail ("assert (X,Y)", "\(1,2,3\).*Abs err 1.5 exceeds tol 0"); ## must give a small tolerance for floating point errors on relative %!assert (100+100*eps, 100, -2*eps) %!assert (100, 100+100*eps, -2*eps) -%!error assert (100+300*eps, 100, -2*eps) -%!error assert (100, 100+300*eps, -2*eps) -%!error assert (3, [3,3]) -%!error assert (3, 4) +%!error <Rel err .* exceeds tol> assert (100+300*eps, 100, -2*eps) +%!error <Rel err .* exceeds tol> assert (100, 100+300*eps, -2*eps) ## test relative vs. absolute tolerances -%!test assert (0.1+eps, 0.1, 2*eps); # accept absolute -%!error assert (0.1+eps, 0.1, -2*eps); # fail relative -%!test assert (100+100*eps, 100, -2*eps); # accept relative -%!error assert (100+100*eps, 100, 2*eps); # fail absolute +%!test assert (0.1+eps, 0.1, 2*eps); +%!error <Rel err 2.2204e-15 exceeds tol> assert (0.1+eps, 0.1, -2*eps); +%!test assert (100+100*eps, 100, -2*eps); +%!error <Abs err 2.8422e-14 exceeds tol> assert (100+100*eps, 100, 2*eps); + +## Corner case of relative tolerance with 0 divider +%!error <Abs err 2 exceeds tol 0.1> assert (2, 0, -0.1) + +## Extra checking of inputs when tolerance unspecified. +%!error <Class single != double> assert (single (1), 1) +%!error <Class uint8 != uint16> assert (uint8 (1), uint16 (1)) +%!error <sparse != non-sparse> assert (sparse([1]), [1]) +%!error <non-sparse != sparse> assert ([1], sparse([1])) +%!error <complex != real> assert (1+i, 1) +%!error <real != complex> assert (1, 1+i) ## exceptional values %!assert ([NaN, NA, Inf, -Inf, 1+eps, eps], [NaN, NA, Inf, -Inf, 1, 0], eps) -%!error assert (NaN, 1) -%!error assert ([NaN 1], [1 NaN]) -%!error assert (NA, 1) + +%!error <'NaN' mismatch> assert (NaN, 1) +%!error <'NaN' mismatch> assert ([NaN 1], [1 NaN]) +%!test +%! try +%! assert ([NaN 1], [1 NaN]); +%! catch +%! errmsg = lasterr (); +%! if (sum (errmsg () == "\n") != 4) +%! error ("Too many errors reported for NaN assert"); +%! elseif (strfind (errmsg, "NA")) +%! error ("NA reported for NaN assert"); +%! elseif (strfind (errmsg, "Abs err NaN exceeds tol 0")) +%! error ("Abs err reported for NaN assert"); +%! endif +%! end_try_catch + +%!error <'NA' mismatch> assert (NA, 1) %!error assert ([NA 1]', [1 NA]') +%!test +%! try +%! assert ([NA 1]', [1 NA]'); +%! catch +%! errmsg = lasterr (); +%! if (sum (errmsg () == "\n") != 4) +%! error ("Too many errors reported for NA assert"); +%! elseif (strfind (errmsg, "NaN")) +%! error ("NaN reported for NA assert"); +%! elseif (strfind (errmsg, "Abs err NA exceeds tol 0")) +%! error ("Abs err reported for NA assert"); +%! endif +%! end_try_catch %!error assert ([(complex (NA, 1)) (complex (2, NA))], [(complex (NA, 2)) 2]) -%!error assert (-Inf, Inf) -%!error assert ([-Inf Inf], [Inf -Inf]) -%!error assert (complex (Inf, 0.2), complex (-Inf, 0.2 + 2*eps), eps) + +%!error <'Inf' mismatch> assert (-Inf, Inf) +%!error <'Inf' mismatch> assert ([-Inf Inf], [Inf -Inf]) +%!test +%! try +%! assert (complex (Inf, 0.2), complex (-Inf, 0.2 + 2*eps), eps); +%! catch +%! errmsg = lasterr (); +%! if (sum (errmsg () == "\n") != 3) +%! error ("Too many errors reported for Inf assert"); +%! elseif (strfind (errmsg, "Abs err")) +%! error ("Abs err reported for Inf assert"); +%! endif +%! end_try_catch +%!error <Abs err> assert (complex (Inf, 0.2), complex (Inf, 0.2 + 2*eps), eps) ## strings %!assert ("dog", "dog") -%!error assert ("dog", "cat") -%!error assert ("dog", 3) -%!error assert (3, "dog") -%!error assert (cellstr ("dog"), "dog") -%!error assert (cell2struct ({"dog"; 3}, {"pet", "age"}, 1), "dog"); - -## structures -%!shared x,y -%! x.a = 1; x.b=[2, 2]; -%! y.a = 1; y.b=[2, 2]; -%!assert (x, y) -%!test y.b=3; -%!error assert (x, y) -%!error assert (3, x) -%!error assert (x, 3) -%!test -%! # Empty structures -%! x = resize (x, 0, 1); -%! y = resize (y, 0, 1); -%! assert (x, y); +%!error <Strings don't match> assert ("dog", "cat") +%!error <Expected string, but observed number> assert (3, "dog") +%!error <Class char != double> assert ("dog", [3 3 3]) +%!error <Expected string, but observed cell> assert ({"dog"}, "dog") +%!error <Expected string, but observed struct> assert (struct ("dog", 3), "dog") ## cell arrays +%!error <Expected cell, but observed double> assert (1, {1}) +%!error <Dimensions don't match> assert (cell (1,2,3), cell (3,2,1)) +%!test +%! x = {{{1}}, 2}; # cell with multiple levels +%! y = x; +%! assert (x,y); +%! y{1}{1}{1} = 3; +%! fail ("assert (x,y)", "Abs err 2 exceeds tol 0"); + %!test %! x = {[3], [1,2,3]; 100+100*eps, "dog"}; %! y = x; @@ -479,7 +546,39 @@ %! y = x; y(1,1) = [2]; y(1,2) = [0, 2, 3]; y(2,1) = 101; y(2,2) = "cat"; %! fail ("assert (x, y)"); -## variable tolerance +## structures +%!error <Expected struct, but observed double> assert (1, struct ("a", 1)) +%!error <Structure sizes don't match> +%! x(1,2,3).a = 1; +%! y(1,2).a = 1; +%! assert (x,y); +%!error <Structure sizes don't match> +%! x(1,2,3).a = 1; +%! y(3,2,2).a = 1; +%! assert (x,y); +%!error <Structure sizes don't match> +%! x.a = 1; x.b = 1; +%! y.a = 1; +%! assert (x,y); +%!error <'b' is not an expected field> +%! x.b = 1; +%! y.a = 1; +%! assert (x,y); + +%!test +%! x.a = 1; x.b=[2, 2]; +%! y.a = 1; y.b=[2, 2]; +%! assert (x, y); +%! y.b=3; +%! fail ("assert (x, y)"); +%! fail ("assert (3, x)"); +%! fail ("assert (x, 3)"); +%! ## Empty structures +%! x = resize (x, 0, 1); +%! y = resize (y, 0, 1); +%! assert (x, y); + +## vector of tolerances %!test %! x = [-40:0]; %! y1 = (10.^x).*(10.^x); @@ -487,6 +586,24 @@ %! assert (y1, y2, eps (y1)); %! fail ("assert (y1, y2 + eps*1e-70, eps (y1))"); +## Multiple tolerances +%!test +%! x = [1 2; 3 4]; +%! y = [0 -1; 1 2]; +%! tol = [-0.1 0; -0.2 0.3]; +%! try +%! assert (x, y, tol); +%! catch +%! errmsg = lasterr (); +%! if (sum (errmsg () == "\n") != 6) +%! error ("Incorrect number of errors reported"); +%! endif +%! assert (!isempty (regexp (errmsg, '\(1,2\).*Abs err 3 exceeds tol 0\>'))); +%! assert (!isempty (regexp (errmsg, '\(2,2\).*Abs err 2 exceeds tol 0.3'))); +%! assert (!isempty (regexp (errmsg, '\(1,1\).*Abs err 1 exceeds tol 0.1'))); +%! assert (!isempty (regexp (errmsg, '\(2,1\).*Rel err 2 exceeds tol 0.2'))); +%! end_try_catch + ## test input validation %!error assert () %!error assert (1,2,3,4)