Mercurial > hg > octave-nkf
annotate scripts/testfun/assert.m @ 7703:e44e4cd2129d
Don't allow the use of lists in assert.m
author | David Bateman <dbateman@free.fr> |
---|---|
date | Wed, 09 Apr 2008 12:40:06 -0400 |
parents | 3422f39573b1 |
children | c6a1a217ac3c |
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 | |
80 elseif (ischar (expected)) | |
6494 | 81 iserror = (! ischar (cond) || ! strcmp (cond, expected)); |
5589 | 82 |
6494 | 83 elseif (iscell (expected)) |
84 if (! iscell (cond) || any (size (cond) != size (expected))) | |
5589 | 85 iserror = 1; |
86 else | |
87 try | |
6494 | 88 for i = 1:length (expected(:)) |
89 assert (cond{i}, expected{i}, tol); | |
5589 | 90 endfor |
91 catch | |
92 iserror = 1; | |
7151 | 93 end_try_catch |
5589 | 94 endif |
95 | |
96 elseif (isstruct (expected)) | |
6494 | 97 if (! isstruct (cond) || any (size (cond) != size (expected)) |
98 || rows(struct_elements (cond)) != rows (struct_elements (expected))) | |
5589 | 99 iserror = 1; |
100 else | |
101 try | |
6494 | 102 empty = numel (cond) == 0; |
103 normal = numel (cond) == 1; | |
104 for [v, k] = cond | |
105 if (! struct_contains (expected, k)) | |
106 error (); | |
107 endif | |
108 if (empty) | |
109 v = cell (1, 0); | |
110 endif | |
111 if (normal) | |
112 v = {v}; | |
113 else | |
114 v = v(:)'; | |
115 endif | |
116 assert (v, {expected.(k)}, tol); | |
5589 | 117 endfor |
118 catch | |
119 iserror = 1; | |
7151 | 120 end_try_catch |
5589 | 121 endif |
122 | |
6392 | 123 elseif (ndims (cond) != ndims (expected) |
124 || any (size (cond) != size (expected))) | |
5589 | 125 iserror = 1; |
126 coda = "Dimensions don't match"; | |
127 | |
6494 | 128 elseif (tol == 0 && ! strcmp (typeinfo (cond), typeinfo (expected))) |
5589 | 129 iserror = 1; |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
130 coda = cstrcat ("Type ", typeinfo (cond), " != ", typeinfo (expected)); |
5589 | 131 |
132 else # numeric | |
6494 | 133 A = cond(:); |
134 B = expected(:); | |
5589 | 135 ## Check exceptional values |
6494 | 136 if (any (isna (A) != isna (B))) |
137 iserror = 1; | |
138 coda = "NAs don't match"; | |
139 elseif (any (isnan (A) != isnan (B))) | |
5589 | 140 iserror = 1; |
141 coda = "NaNs don't match"; | |
6494 | 142 ### Try to avoid problems comparing strange values like Inf+NaNi. |
143 elseif (any (isinf (A) != isinf (B)) | |
144 || any (A(isinf (A) & ! isnan (A)) != B(isinf (B) & ! isnan (B)))) | |
5589 | 145 iserror = 1; |
146 coda = "Infs don't match"; | |
147 else | |
148 ## Check normal values | |
6494 | 149 A = A(finite (A)); |
150 B = B(finite (B)); | |
151 if (tol == 0) | |
152 err = any (A != B); | |
5589 | 153 errtype = "values do not match"; |
6494 | 154 elseif (tol >= 0) |
155 err = max (abs (A - B)); | |
5589 | 156 errtype = "maximum absolute error %g exceeds tolerance %g"; |
157 else | |
6494 | 158 abserr = max (abs (A(B == 0))); |
159 A = A(B != 0); | |
160 B = B(B != 0); | |
161 relerr = max (abs (A - B) ./ abs (B)); | |
162 err = max ([abserr; relerr]); | |
5589 | 163 errtype = "maximum relative error %g exceeds tolerance %g"; |
164 endif | |
6494 | 165 if (err > abs (tol)) |
5589 | 166 iserror = 1; |
6494 | 167 coda = sprintf (errtype, err, abs (tol)); |
5589 | 168 endif |
169 endif | |
170 endif | |
171 | |
6494 | 172 if (! iserror) |
5589 | 173 return; |
174 endif | |
175 | |
176 ## pretty print the "expected but got" info, | |
177 ## trimming leading and trailing "\n" | |
178 str = disp (expected); | |
6494 | 179 idx = find (str != "\n"); |
180 if (! isempty (idx)) | |
181 str = str(idx(1):idx(end)); | |
5589 | 182 endif |
183 str2 = disp (cond); | |
6494 | 184 idx = find (str2 != "\n"); |
185 if (! isempty (idx)) | |
186 str2 = str2 (idx(1):idx(end)); | |
5589 | 187 endif |
7540
3422f39573b1
strcat.m: Matlab compatibility, with cstrcat.m replacing conventional strcat.m.
Ben Abbott <bpabbott@mac.com>
parents:
7151
diff
changeset
|
188 msg = cstrcat ("assert ", in, " expected\n", str, "\nbut got\n", str2); |
6494 | 189 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
|
190 msg = cstrcat (msg, "\n", coda); |
5589 | 191 endif |
6494 | 192 error ("%s", msg); |
193 ## disp (msg); | |
194 ## error ("assertion failed"); | |
5589 | 195 endfunction |
196 | |
197 ## empty | |
198 %!assert([]) | |
199 %!assert(zeros(3,0),zeros(3,0)) | |
200 %!error assert(zeros(3,0),zeros(0,2)) | |
201 %!error assert(zeros(3,0),[]) | |
6455 | 202 %!fail("assert(zeros(2,0,2),zeros(2,0))", "Dimensions don't match") |
5589 | 203 |
204 ## conditions | |
205 %!assert(isempty([])) | |
206 %!assert(1) | |
207 %!error assert(0) | |
208 %!assert(ones(3,1)) | |
209 %!assert(ones(1,3)) | |
210 %!assert(ones(3,4)) | |
211 %!error assert([1,0,1]) | |
212 %!error assert([1;1;0]) | |
213 %!error assert([1,0;1,1]) | |
214 | |
215 ## vectors | |
216 %!assert([1,2,3],[1,2,3]); | |
217 %!assert([1;2;3],[1;2;3]); | |
218 %!error assert([2;2;3],[1;2;3]); | |
219 %!error assert([1,2,3],[1;2;3]); | |
220 %!error assert([1,2],[1,2,3]); | |
221 %!error assert([1;2;3],[1;2]); | |
222 %!assert([1,2;3,4],[1,2;3,4]); | |
223 %!error assert([1,4;3,4],[1,2;3,4]) | |
224 %!error assert([1,3;2,4;3,5],[1,2;3,4]) | |
225 | |
226 ## exceptional values | |
227 %!assert([NaN, NA, Inf, -Inf, 1+eps, eps],[NaN, NA, Inf, -Inf, 1, 0],eps) | |
228 %!error assert(NaN, 1) | |
229 %!error assert(NA, 1) | |
230 %!error assert(-Inf, Inf) | |
231 | |
232 ## scalars | |
233 %!error assert(3, [3,3; 3,3]) | |
234 %!error assert([3,3; 3,3], 3) | |
235 %!assert(3, 3); | |
236 %!assert(3+eps, 3, eps); | |
237 %!assert(3, 3+eps, eps); | |
238 %!error assert(3+2*eps, 3, eps); | |
239 %!error assert(3, 3+2*eps, eps); | |
240 | |
7027 | 241 ## must give a little space for floating point errors on relative |
5589 | 242 %!assert(100+100*eps, 100, -2*eps); |
243 %!assert(100, 100+100*eps, -2*eps); | |
244 %!error assert(100+300*eps, 100, -2*eps); | |
245 %!error assert(100, 100+300*eps, -2*eps); | |
246 %!error assert(3, [3,3]); | |
247 %!error assert(3,4); | |
248 | |
7027 | 249 ## test relative vs. absolute tolerances |
250 %!test assert (0.1+eps, 0.1, 2*eps); # accept absolute | |
251 %!error assert (0.1+eps, 0.1, -2*eps); # fail relative | |
252 %!test assert (100+100*eps, 100, -2*eps); # accept relative | |
253 %!error assert (100+100*eps, 100, 2*eps); # fail absolute | |
254 | |
5589 | 255 ## structures |
256 %!shared x,y | |
257 %! x.a = 1; x.b=[2, 2]; | |
258 %! y.a = 1; y.b=[2, 2]; | |
259 %!assert (x,y) | |
260 %!test y.b=3; | |
261 %!error assert (x,y) | |
262 %!error assert (3, x); | |
263 %!error assert (x, 3); | |
264 | |
265 ## check usage statements | |
266 %!error assert | |
267 %!error assert(1,2,3,4,5) | |
268 | |
269 ## strings | |
270 %!assert("dog","dog") | |
271 %!error assert("dog","cat") | |
272 %!error assert("dog",3); | |
273 %!error assert(3,"dog"); |