Mercurial > hg > octave-lyh
annotate scripts/testfun/assert.m @ 7583:1d7c23e288d7
__go_draw_axes__: use strcmpi for text properties; use get for hidden properties
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 11 Mar 2008 23:12:17 -0400 |
parents | 3422f39573b1 |
children | e44e4cd2129d |
rev | line source |
---|---|
7017 | 1 ## Copyright (C) 2000, 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} {} assert (@var{cond}) | |
21 ## @deftypefnx {Function File} {} assert (@var{observed},@var{expected}) | |
22 ## @deftypefnx {Function File} {} assert (@var{observed},@var{expected},@var{tol}) | |
23 ## | |
24 ## Produces an error if the condition is not met. @code{assert} can be | |
25 ## called in three different ways. | |
26 ## | |
27 ## @table @code | |
28 ## @item assert (@var{cond}) | |
29 ## Called with a single argument @var{cond}, @code{assert} produces an | |
30 ## error if @var{cond} is zero. | |
31 ## | |
32 ## @item assert (@var{observed}, @var{expected}) | |
33 ## Produce an error if observed is not the same as expected. Note that | |
34 ## observed and expected can be strings, scalars, vectors, matrices, | |
35 ## lists or structures. | |
36 ## | |
37 ## @item assert(@var{observed}, @var{expected}, @var{tol}) | |
7027 | 38 ## Accept a tolerance when comparing numbers. |
39 ## If @var{tol} is possitive use it as an absolute tolerance, will produce an error if | |
40 ## @code{abs(@var{observed} - @var{expected}) > abs(@var{tol})}. | |
41 ## If @var{tol} is negative use it as a relative tolerance, will produce an error if | |
42 ## @code{abs(@var{observed} - @var{expected}) > abs(@var{tol} * @var{expected})}. | |
43 ## If @var{expected} is zero @var{tol} will always be used as an absolute tolerance. | |
5589 | 44 ## @end table |
5642 | 45 ## @seealso{test} |
5589 | 46 ## @end deftypefn |
47 | |
48 ## TODO: Output throttling: don't print out the entire 100x100 matrix, | |
49 ## TODO: but instead give a summary; don't print out the whole list, just | |
50 ## TODO: say what the first different element is, etc. To do this, make | |
51 ## TODO: the message generation type specific. | |
6494 | 52 |
53 function assert (cond, expected, tol) | |
5589 | 54 |
55 if (nargin < 1 || nargin > 3) | |
6046 | 56 print_usage (); |
5589 | 57 endif |
58 | |
59 if (nargin < 3) | |
60 tol = 0; | |
61 endif | |
62 | |
6494 | 63 if (exist ("argn") == 0) |
64 argn = " "; | |
65 endif | |
66 | |
67 in = deblank (argn(1,:)); | |
68 for i = 2:rows (argn) | |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
69 in = cstrcat (in, ",", deblank (argn(i,:))); |
7151 | 70 endfor |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
71 in = cstrcat ("(", in, ")"); |
5589 | 72 |
73 coda = ""; | |
74 iserror = 0; | |
75 if (nargin == 1) | |
6494 | 76 if (! isnumeric (cond) || ! all (cond(:))) |
5589 | 77 error ("assert %s failed", in); # say which elements failed? |
78 endif | |
79 | |
6494 | 80 elseif (is_list (cond)) |
81 if (! is_list (expected) || length (cond) != length (expected)) | |
5589 | 82 iserror = 1; |
83 else | |
84 try | |
6494 | 85 for i = 1:length (cond) |
86 assert (nth (cond, i), nth (expected, i)); | |
5589 | 87 endfor |
88 catch | |
89 iserror = 1; | |
7151 | 90 end_try_catch |
5589 | 91 endif |
92 | |
93 elseif (ischar (expected)) | |
6494 | 94 iserror = (! ischar (cond) || ! strcmp (cond, expected)); |
5589 | 95 |
6494 | 96 elseif (iscell (expected)) |
97 if (! iscell (cond) || any (size (cond) != size (expected))) | |
5589 | 98 iserror = 1; |
99 else | |
100 try | |
6494 | 101 for i = 1:length (expected(:)) |
102 assert (cond{i}, expected{i}, tol); | |
5589 | 103 endfor |
104 catch | |
105 iserror = 1; | |
7151 | 106 end_try_catch |
5589 | 107 endif |
108 | |
109 elseif (isstruct (expected)) | |
6494 | 110 if (! isstruct (cond) || any (size (cond) != size (expected)) |
111 || rows(struct_elements (cond)) != rows (struct_elements (expected))) | |
5589 | 112 iserror = 1; |
113 else | |
114 try | |
6494 | 115 empty = numel (cond) == 0; |
116 normal = numel (cond) == 1; | |
117 for [v, k] = cond | |
118 if (! struct_contains (expected, k)) | |
119 error (); | |
120 endif | |
121 if (empty) | |
122 v = cell (1, 0); | |
123 endif | |
124 if (normal) | |
125 v = {v}; | |
126 else | |
127 v = v(:)'; | |
128 endif | |
129 assert (v, {expected.(k)}, tol); | |
5589 | 130 endfor |
131 catch | |
132 iserror = 1; | |
7151 | 133 end_try_catch |
5589 | 134 endif |
135 | |
6392 | 136 elseif (ndims (cond) != ndims (expected) |
137 || any (size (cond) != size (expected))) | |
5589 | 138 iserror = 1; |
139 coda = "Dimensions don't match"; | |
140 | |
6494 | 141 elseif (tol == 0 && ! strcmp (typeinfo (cond), typeinfo (expected))) |
5589 | 142 iserror = 1; |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
143 coda = cstrcat ("Type ", typeinfo (cond), " != ", typeinfo (expected)); |
5589 | 144 |
145 else # numeric | |
6494 | 146 A = cond(:); |
147 B = expected(:); | |
5589 | 148 ## Check exceptional values |
6494 | 149 if (any (isna (A) != isna (B))) |
150 iserror = 1; | |
151 coda = "NAs don't match"; | |
152 elseif (any (isnan (A) != isnan (B))) | |
5589 | 153 iserror = 1; |
154 coda = "NaNs don't match"; | |
6494 | 155 ### Try to avoid problems comparing strange values like Inf+NaNi. |
156 elseif (any (isinf (A) != isinf (B)) | |
157 || any (A(isinf (A) & ! isnan (A)) != B(isinf (B) & ! isnan (B)))) | |
5589 | 158 iserror = 1; |
159 coda = "Infs don't match"; | |
160 else | |
161 ## Check normal values | |
6494 | 162 A = A(finite (A)); |
163 B = B(finite (B)); | |
164 if (tol == 0) | |
165 err = any (A != B); | |
5589 | 166 errtype = "values do not match"; |
6494 | 167 elseif (tol >= 0) |
168 err = max (abs (A - B)); | |
5589 | 169 errtype = "maximum absolute error %g exceeds tolerance %g"; |
170 else | |
6494 | 171 abserr = max (abs (A(B == 0))); |
172 A = A(B != 0); | |
173 B = B(B != 0); | |
174 relerr = max (abs (A - B) ./ abs (B)); | |
175 err = max ([abserr; relerr]); | |
5589 | 176 errtype = "maximum relative error %g exceeds tolerance %g"; |
177 endif | |
6494 | 178 if (err > abs (tol)) |
5589 | 179 iserror = 1; |
6494 | 180 coda = sprintf (errtype, err, abs (tol)); |
5589 | 181 endif |
182 endif | |
183 endif | |
184 | |
6494 | 185 if (! iserror) |
5589 | 186 return; |
187 endif | |
188 | |
189 ## pretty print the "expected but got" info, | |
190 ## trimming leading and trailing "\n" | |
191 str = disp (expected); | |
6494 | 192 idx = find (str != "\n"); |
193 if (! isempty (idx)) | |
194 str = str(idx(1):idx(end)); | |
5589 | 195 endif |
196 str2 = disp (cond); | |
6494 | 197 idx = find (str2 != "\n"); |
198 if (! isempty (idx)) | |
199 str2 = str2 (idx(1):idx(end)); | |
5589 | 200 endif |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
201 msg = cstrcat ("assert ", in, " expected\n", str, "\nbut got\n", str2); |
6494 | 202 if (! isempty (coda)) |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
203 msg = cstrcat (msg, "\n", coda); |
5589 | 204 endif |
6494 | 205 error ("%s", msg); |
206 ## disp (msg); | |
207 ## error ("assertion failed"); | |
5589 | 208 endfunction |
209 | |
210 ## empty | |
211 %!assert([]) | |
212 %!assert(zeros(3,0),zeros(3,0)) | |
213 %!error assert(zeros(3,0),zeros(0,2)) | |
214 %!error assert(zeros(3,0),[]) | |
6455 | 215 %!fail("assert(zeros(2,0,2),zeros(2,0))", "Dimensions don't match") |
5589 | 216 |
217 ## conditions | |
218 %!assert(isempty([])) | |
219 %!assert(1) | |
220 %!error assert(0) | |
221 %!assert(ones(3,1)) | |
222 %!assert(ones(1,3)) | |
223 %!assert(ones(3,4)) | |
224 %!error assert([1,0,1]) | |
225 %!error assert([1;1;0]) | |
226 %!error assert([1,0;1,1]) | |
227 | |
228 ## vectors | |
229 %!assert([1,2,3],[1,2,3]); | |
230 %!assert([1;2;3],[1;2;3]); | |
231 %!error assert([2;2;3],[1;2;3]); | |
232 %!error assert([1,2,3],[1;2;3]); | |
233 %!error assert([1,2],[1,2,3]); | |
234 %!error assert([1;2;3],[1;2]); | |
235 %!assert([1,2;3,4],[1,2;3,4]); | |
236 %!error assert([1,4;3,4],[1,2;3,4]) | |
237 %!error assert([1,3;2,4;3,5],[1,2;3,4]) | |
238 | |
239 ## exceptional values | |
240 %!assert([NaN, NA, Inf, -Inf, 1+eps, eps],[NaN, NA, Inf, -Inf, 1, 0],eps) | |
241 %!error assert(NaN, 1) | |
242 %!error assert(NA, 1) | |
243 %!error assert(-Inf, Inf) | |
244 | |
245 ## scalars | |
246 %!error assert(3, [3,3; 3,3]) | |
247 %!error assert([3,3; 3,3], 3) | |
248 %!assert(3, 3); | |
249 %!assert(3+eps, 3, eps); | |
250 %!assert(3, 3+eps, eps); | |
251 %!error assert(3+2*eps, 3, eps); | |
252 %!error assert(3, 3+2*eps, eps); | |
253 | |
7027 | 254 ## must give a little space for floating point errors on relative |
5589 | 255 %!assert(100+100*eps, 100, -2*eps); |
256 %!assert(100, 100+100*eps, -2*eps); | |
257 %!error assert(100+300*eps, 100, -2*eps); | |
258 %!error assert(100, 100+300*eps, -2*eps); | |
259 %!error assert(3, [3,3]); | |
260 %!error assert(3,4); | |
261 | |
7027 | 262 ## test relative vs. absolute tolerances |
263 %!test assert (0.1+eps, 0.1, 2*eps); # accept absolute | |
264 %!error assert (0.1+eps, 0.1, -2*eps); # fail relative | |
265 %!test assert (100+100*eps, 100, -2*eps); # accept relative | |
266 %!error assert (100+100*eps, 100, 2*eps); # fail absolute | |
267 | |
5589 | 268 ## structures |
269 %!shared x,y | |
270 %! x.a = 1; x.b=[2, 2]; | |
271 %! y.a = 1; y.b=[2, 2]; | |
272 %!assert (x,y) | |
273 %!test y.b=3; | |
274 %!error assert (x,y) | |
275 %!error assert (3, x); | |
276 %!error assert (x, 3); | |
277 | |
278 ## check usage statements | |
279 %!error assert | |
280 %!error assert(1,2,3,4,5) | |
281 | |
282 ## strings | |
283 %!assert("dog","dog") | |
284 %!error assert("dog","cat") | |
285 %!error assert("dog",3); | |
286 %!error assert(3,"dog"); |