# HG changeset patch # User John W. Eaton # Date 1394215363 18000 # Node ID b83fca22bb4cd4dc052bac915069eed3327800d8 # Parent 2f5685c080e5c5591db55e58ff298a9254ab5ae9# Parent de76baa76aa199f6bc1378c86f3996b6168d942f maint: Periodic merge of gui-release to default. diff -r 2f5685c080e5 -r b83fca22bb4c .hgtags --- a/.hgtags Tue Mar 04 11:10:42 2014 -0500 +++ b/.hgtags Fri Mar 07 13:02:43 2014 -0500 @@ -86,3 +86,4 @@ 85d31344fb23725791bc687337295d47416b9c17 rc-3-8-1-2 02ce68d63fba31cd14ac060c087212a032ae3202 rc-3-8-1-3 dd669c2ae76c167613f54d6f4db0130fa2124cac rc-3-8-1-4 +43cc202335dc4a53a3d8fc9ca90acaa81d2e63d3 release-3-8-1 diff -r 2f5685c080e5 -r b83fca22bb4c configure.ac diff -r 2f5685c080e5 -r b83fca22bb4c libgui/src/m-editor/file-editor.cc --- a/libgui/src/m-editor/file-editor.cc Tue Mar 04 11:10:42 2014 -0500 +++ b/libgui/src/m-editor/file-editor.cc Fri Mar 07 13:02:43 2014 -0500 @@ -42,6 +42,7 @@ #include "octave-link.h" #include "utils.h" +#include "main-window.h" file_editor::file_editor (QWidget *p) : file_editor_interface (p) @@ -266,6 +267,23 @@ return false; } +bool +file_editor::is_editor_console_tabbed () +{ + main_window *w = static_cast(main_win ()); + QList w_list = w->tabifiedDockWidgets (this); + QDockWidget *console = + static_cast (w->get_dock_widget_list ().at (0)); + + for (int i = 0; i < w_list.count (); i++) + { + if (w_list.at (i) == console) + return true; + } + + return false; +} + void file_editor::request_open_files (const QStringList& open_file_names) { @@ -311,8 +329,11 @@ emit fetab_do_breakpoint_marker (insert, tab, line); } - emit fetab_set_focus (tab); - set_focus (); + if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) + { + emit fetab_set_focus (tab); + set_focus (); + } } else { @@ -411,9 +432,12 @@ } } - // really show editor and the current editor tab - set_focus (); - emit file_loaded_signal (); + if (! ((breakpoint_marker || debug_pointer) && is_editor_console_tabbed ())) + { + // really show editor and the current editor tab + set_focus (); + emit file_loaded_signal (); + } } } } diff -r 2f5685c080e5 -r b83fca22bb4c libgui/src/m-editor/file-editor.h --- a/libgui/src/m-editor/file-editor.h Tue Mar 04 11:10:42 2014 -0500 +++ b/libgui/src/m-editor/file-editor.h Fri Mar 07 13:02:43 2014 -0500 @@ -195,6 +195,7 @@ private: + bool is_editor_console_tabbed (); void construct (void); void add_file_editor_tab (file_editor_tab *f, const QString& fn); void save_file_as (QWidget *fetabID = 0); diff -r 2f5685c080e5 -r b83fca22bb4c libgui/src/main-window.h --- a/libgui/src/main-window.h Tue Mar 04 11:10:42 2014 -0500 +++ b/libgui/src/main-window.h Fri Mar 07 13:02:43 2014 -0500 @@ -198,6 +198,9 @@ void clipboard_has_changed (QClipboard::Mode); void clear_clipboard (); + // get the dockwidgets + QList get_dock_widget_list () + { return dock_widget_list (); } protected: void closeEvent (QCloseEvent * closeEvent); diff -r 2f5685c080e5 -r b83fca22bb4c libinterp/dldfcn/__magick_read__.cc --- a/libinterp/dldfcn/__magick_read__.cc Tue Mar 04 11:10:42 2014 -0500 +++ b/libinterp/dldfcn/__magick_read__.cc Fri Mar 07 13:02:43 2014 -0500 @@ -416,6 +416,7 @@ } } + const octave_idx_type colour_stride = nRows * nCols; switch (type) { case Magick::BilevelType: // Monochrome bi-level image @@ -480,6 +481,7 @@ img = T (dim_vector (nRows, nCols, 3, nFrames)); P *img_fvec = img.fortran_vec (); + const octave_idx_type frame_stride = colour_stride * 3; for (octave_idx_type frame = 0; frame < nFrames; frame++) { const Magick::PixelPacket *pix @@ -487,10 +489,9 @@ col_cache, row_cache); octave_idx_type idx = 0; - img_fvec += nRows * nCols * frame; P *rbuf = img_fvec; - P *gbuf = img_fvec + nRows * nCols; - P *bbuf = img_fvec + nRows * nCols * 2; + P *gbuf = img_fvec + colour_stride; + P *bbuf = img_fvec + colour_stride * 2; for (octave_idx_type col = 0; col < nCols; col++) { @@ -504,6 +505,7 @@ } pix -= col_shift; } + img_fvec += frame_stride; } break; } @@ -516,6 +518,8 @@ P *img_fvec = img.fortran_vec (); P *a_fvec = alpha.fortran_vec (); + const octave_idx_type frame_stride = colour_stride * 3; + // Unlike the index for the other channels, this one won't need // to be reset on each frame since it's a separate matrix. octave_idx_type a_idx = 0; @@ -526,10 +530,9 @@ col_cache, row_cache); octave_idx_type idx = 0; - img_fvec += nRows * nCols * frame; P *rbuf = img_fvec; - P *gbuf = img_fvec + nRows * nCols; - P *bbuf = img_fvec + nRows * nCols * 2; + P *gbuf = img_fvec + colour_stride; + P *bbuf = img_fvec + colour_stride * 2; for (octave_idx_type col = 0; col < nCols; col++) { @@ -544,6 +547,7 @@ } pix -= col_shift; } + img_fvec += frame_stride; } retval(2) = alpha; break; @@ -554,6 +558,7 @@ img = T (dim_vector (nRows, nCols, 4, nFrames)); P *img_fvec = img.fortran_vec (); + const octave_idx_type frame_stride = colour_stride * 4; for (octave_idx_type frame = 0; frame < nFrames; frame++) { const Magick::PixelPacket *pix @@ -561,11 +566,10 @@ col_cache, row_cache); octave_idx_type idx = 0; - img_fvec += nRows * nCols * frame; P *cbuf = img_fvec; - P *mbuf = img_fvec + nRows * nCols; - P *ybuf = img_fvec + nRows * nCols * 2; - P *kbuf = img_fvec + nRows * nCols * 3; + P *mbuf = img_fvec + colour_stride; + P *ybuf = img_fvec + colour_stride * 2; + P *kbuf = img_fvec + colour_stride * 3; for (octave_idx_type col = 0; col < nCols; col++) { @@ -580,6 +584,7 @@ } pix -= col_shift; } + img_fvec += frame_stride; } break; } @@ -592,6 +597,8 @@ P *img_fvec = img.fortran_vec (); P *a_fvec = alpha.fortran_vec (); + const octave_idx_type frame_stride = colour_stride * 4; + // Unlike the index for the other channels, this one won't need // to be reset on each frame since it's a separate matrix. octave_idx_type a_idx = 0; @@ -606,11 +613,10 @@ = imvec[frameidx(frame)].getConstIndexes (); octave_idx_type idx = 0; - img_fvec += nRows * nCols * frame; P *cbuf = img_fvec; - P *mbuf = img_fvec + nRows * nCols; - P *ybuf = img_fvec + nRows * nCols * 2; - P *kbuf = img_fvec + nRows * nCols * 3; + P *mbuf = img_fvec + colour_stride; + P *ybuf = img_fvec + colour_stride * 2; + P *kbuf = img_fvec + colour_stride * 3; for (octave_idx_type col = 0; col < nCols; col++) { @@ -626,6 +632,7 @@ } pix -= col_shift; } + img_fvec += frame_stride; } retval(2) = alpha; break; @@ -1062,7 +1069,6 @@ { case Magick::GrayscaleType: { - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1070,6 +1076,7 @@ Magick::DirectClass); Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) @@ -1091,7 +1098,6 @@ case Magick::GrayscaleMatteType: { - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1099,13 +1105,14 @@ Magick::DirectClass); Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) { - Magick::Color c; - c.redQuantum (double (*img_fvec) / divisor); - c.alphaQuantum (MaxRGB - (double (*a_fvec) / divisor)); + double grey = double (*img_fvec) / divisor; + Magick::Color c (grey, grey, grey, + MaxRGB - (double (*a_fvec) / divisor)); pix[GM_idx] = c; img_fvec++; a_fvec++; @@ -1125,7 +1132,6 @@ // The fortran_vec offset for the green and blue channels const octave_idx_type G_offset = nCols * nRows; const octave_idx_type B_offset = nCols * nRows * 2; - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1133,6 +1139,7 @@ Magick::DirectClass); Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) @@ -1149,6 +1156,7 @@ // Save changes to underlying image. m_img.syncPixels (); imvec.push_back (m_img); + img_fvec += B_offset; } break; } @@ -1158,7 +1166,6 @@ // The fortran_vec offset for the green and blue channels const octave_idx_type G_offset = nCols * nRows; const octave_idx_type B_offset = nCols * nRows * 2; - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1166,6 +1173,7 @@ Magick::DirectClass); Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) @@ -1184,6 +1192,7 @@ // Save changes to underlying image. m_img.syncPixels (); imvec.push_back (m_img); + img_fvec += B_offset; } break; } @@ -1194,7 +1203,6 @@ const octave_idx_type M_offset = nCols * nRows; const octave_idx_type Y_offset = nCols * nRows * 2; const octave_idx_type K_offset = nCols * nRows * 3; - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1202,6 +1210,7 @@ Magick::DirectClass); Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) @@ -1219,6 +1228,7 @@ // Save changes to underlying image. m_img.syncPixels (); imvec.push_back (m_img); + img_fvec += K_offset; } break; } @@ -1229,7 +1239,6 @@ const octave_idx_type M_offset = nCols * nRows; const octave_idx_type Y_offset = nCols * nRows * 2; const octave_idx_type K_offset = nCols * nRows * 3; - octave_idx_type GM_idx = 0; for (octave_idx_type frame = 0; frame < nFrames; frame++) { Magick::Image m_img = init_enconde_image (nCols, nRows, bitdepth, @@ -1238,6 +1247,7 @@ Magick::PixelPacket *pix = m_img.getPixels (0, 0, nCols, nRows); Magick::IndexPacket *ind = m_img.getIndexes (); + octave_idx_type GM_idx = 0; for (octave_idx_type col = 0; col < nCols; col++) { for (octave_idx_type row = 0; row < nRows; row++) @@ -1257,6 +1267,7 @@ // Save changes to underlying image. m_img.syncPixels (); imvec.push_back (m_img); + img_fvec += K_offset; } break; } diff -r 2f5685c080e5 -r b83fca22bb4c scripts/image/imshow.m --- a/scripts/image/imshow.m Tue Mar 04 11:10:42 2014 -0500 +++ b/scripts/image/imshow.m Fri Mar 07 13:02:43 2014 -0500 @@ -130,7 +130,7 @@ xdata = [xdata(1) xdata(end)]; case "ydata"; ydata = varargin{narg++}; - if (isvector (xdata)) + if (! isvector (ydata)) error ("imshow: expect a vector for ydata") endif ydata = [ydata(1) ydata(end)]; diff -r 2f5685c080e5 -r b83fca22bb4c scripts/image/imwrite.m --- a/scripts/image/imwrite.m Tue Mar 04 11:10:42 2014 -0500 +++ b/scripts/image/imwrite.m Fri Mar 07 13:02:43 2014 -0500 @@ -114,7 +114,6 @@ endfunction - %% Test input validation %!error imwrite () # Wrong # of args %!error imwrite (1) # Wrong # of args @@ -126,14 +125,69 @@ %!error imwrite ([], "filename.jpg") # Empty img matrix %!error imwrite (spones (2), "filename.jpg") # Invalid sparse img +%!function [r, cmap, a] = write_and_read (varargin) +%! filename = [tmpnam() ".tif"]; +%! unwind_protect +%! imwrite (varargin{1}, filename, varargin{2:end}); +%! [r, cmap, a] = imread (filename, "Index", "all"); +%! unwind_protect_cleanup +%! unlink (filename); +%! end_unwind_protect +%!endfunction + +## typical usage with grayscale uint8 images %!testif HAVE_MAGICK -%! imw = randi (255, 100, "uint8"); -%! filename = [tmpnam() ".png"]; -%! unwind_protect -%! imwrite (imw, filename); -%! imr = imread (filename); -%! unwind_protect_cleanup -%! unlink (filename); -%! end_unwind_protect -%! assert (imw, imr) +%! gray = randi (255, 10, 10, 1, "uint8"); +%! r = write_and_read (gray); +%! assert (r, gray) + +## grayscale uint8 images with alpha channel +%!testif HAVE_MAGICK +%! gray = randi (255, 10, 10, 1, "uint8"); +%! alpha = randi (255, 10, 10, 1, "uint8"); +%! [r, ~, a] = write_and_read (gray, "Alpha", alpha); +%! assert (r, gray) +%! assert (a, alpha) + +## multipage grayscale uint8 images +%!testif HAVE_MAGICK +%! gray = randi (255, 10, 10, 1, 5, "uint8"); +%! r = write_and_read (gray); +%! assert (r, gray) + +## multipage RGB uint8 images with alpha channel +%!testif HAVE_MAGICK +%! gray = randi (255, 10, 10, 3, 5, "uint8"); +%! alpha = randi (255, 10, 10, 1, 5, "uint8"); +%! [r, ~, a] = write_and_read (gray, "Alpha", alpha); +%! assert (r, gray) +%! assert (a, alpha) +## typical usage with RGB uint8 images +%!testif HAVE_MAGICK +%! rgb = randi (255, 10, 10, 3, "uint8"); +%! r = write_and_read (rgb); +%! assert (r, rgb) + +## RGB uint8 images with alpha channel +%!testif HAVE_MAGICK +%! rgb = randi (255, 10, 10, 3, "uint8"); +%! alpha = randi (255, 10, 10, 1, "uint8"); +%! [r, ~, a] = write_and_read (rgb, "Alpha", alpha); +%! assert (r, rgb) +%! assert (a, alpha) + +## multipage RGB uint8 images +%!testif HAVE_MAGICK +%! rgb = randi (255, 10, 10, 3, 5, "uint8"); +%! r = write_and_read (rgb); +%! assert (r, rgb) + +## multipage RGB uint8 images with alpha channel +%!testif HAVE_MAGICK +%! rgb = randi (255, 10, 10, 3, 5, "uint8"); +%! alpha = randi (255, 10, 10, 1, 5, "uint8"); +%! [r, ~, a] = write_and_read (rgb, "Alpha", alpha); +%! assert (r, rgb) +%! assert (a, alpha) + diff -r 2f5685c080e5 -r b83fca22bb4c scripts/testfun/assert.m --- a/scripts/testfun/assert.m Tue Mar 04 11:10:42 2014 -0500 +++ b/scripts/testfun/assert.m Fri Mar 07 13:02:43 2014 -0500 @@ -63,269 +63,187 @@ persistent call_depth = -1; persistent errmsg; - call_depth++; - - if (call_depth == 0) - errmsg = ""; - endif + unwind_protect - 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? - argin = ["(" strjoin(cellstr (argn), ",") ")"]; - error ("assert %s failed", argin); - else - error (varargin{:}); - endif - endif - else - expected = varargin{1}; - if (nargin < 3) - tol = 0; - elseif (nargin == 3) - tol = varargin{2}; - else - print_usage (); + call_depth++; + + if (call_depth == 0) + errmsg = ""; endif - ## Add to list as the errors accumulate. If empty at end then no errors. - err.index = {}; - err.observed = {}; - err.expected = {}; - err.reason = {}; - - if (ischar (expected)) - if (! ischar (cond)) - 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"; + if (nargin == 1 || (nargin > 1 && islogical (cond) && ischar (varargin{1}))) + if ((! isnumeric (cond) && ! islogical (cond)) || ! all (cond(:))) + if (nargin == 1) + ## Perhaps, say which elements failed? + argin = ["(" strjoin(cellstr (argn), ",") ")"]; + error ("assert %s failed", argin); else - err.observed{end+1} = "O"; - err.reason{end+1} = ["Expected string, but observed " class(cond)]; + error (varargin{:}); endif - elseif (! strcmp (cond, expected)) - err.index{end+1} = "[]"; - err.observed{end+1} = cond; - err.expected{end+1} = expected; - err.reason{end+1} = "Strings don't match"; + endif + else + expected = varargin{1}; + if (nargin < 3) + tol = 0; + elseif (nargin == 3) + tol = varargin{2}; + else + print_usage (); endif - elseif (iscell (expected)) - if (! iscell (cond)) - err.index{end+1} = "."; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - err.reason{end+1} = ["Expected cell, but observed " class(cond)]; + ## Add to list as the errors accumulate. If empty at end then no errors. + err.index = {}; + err.observed = {}; + err.expected = {}; + err.reason = {}; + + if (ischar (expected)) + if (! ischar (cond)) + 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"; + else + 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; + err.expected{end+1} = expected; + err.reason{end+1} = "Strings don't match"; + endif + + elseif (iscell (expected)) + if (! iscell (cond)) + err.index{end+1} = "."; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + 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 + for i = 1:length (expected(:)) + assert (cond{i}, expected{i}, tol); + endfor + catch + err.index{end+1} = "{}"; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + err.reason{end+1} = "Cell configuration error"; + end_try_catch + endif + + elseif (is_function_handle (expected)) + if (! is_function_handle (cond)) + err.index{end+1} = "@"; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + err.reason{end+1} = ["Expected function handle, but observed " class(cond)]; + elseif (! isequal (cond, expected)) + err.index{end+1} = "@"; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + err.reason{end+1} = "Function handles don't match"; + endif + + elseif (isstruct (expected)) + 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)) + || numfields (cond) != numfields (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 + empty = isempty (cond); + normal = (numel (cond) == 1); + for [v, k] = cond + if (! isfield (expected, k)) + err.index{end+1} = "."; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + err.reason{end+1} = ["'" k "'" " is not an expected field"]; + endif + if (empty) + v = {}; + elseif (normal) + v = {v}; + else + v = v(:)'; + endif + ## Recursively call assert for struct array values + assert (v, {expected.(k)}, tol); + endfor + catch + err.index{end+1} = "."; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + err.reason{end+1} = "Structure configuration error"; + end_try_catch + endif + 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 - for i = 1:length (expected(:)) - assert (cond{i}, expected{i}, tol); - endfor - catch - err.index{end+1} = "{}"; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - err.reason{end+1} = "Cell configuration error"; - end_try_catch - endif - elseif (isstruct (expected)) - 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)) - || numfields (cond) != numfields (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 - empty = isempty (cond); - normal = (numel (cond) == 1); - for [v, k] = cond - if (! isfield (expected, k)) - err.index{end+1} = "."; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - err.reason{end+1} = ["'" k "'" " is not an expected field"]; - endif - if (empty) - v = {}; - elseif (normal) - v = {v}; - else - v = v(:)'; - endif - ## Recursively call assert for struct array values - assert (v, {expected.(k)}, tol); - endfor - catch - err.index{end+1} = "."; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - err.reason{end+1} = "Structure configuration error"; - end_try_catch - endif - - 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 # Numeric comparison - if (nargin < 3) - ## Without explicit tolerance, be more strict. - if (! strcmp (class (cond), class (expected))) - err.index{end+1} = "()"; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - err.reason{end+1} = ["Class " class(cond) " != " class(expected)]; - elseif (isnumeric (cond)) - if (issparse (cond) != issparse (expected)) + else # Numeric comparison + if (nargin < 3) + ## Without explicit tolerance, be more strict. + if (! strcmp (class (cond), class (expected))) err.index{end+1} = "()"; err.observed{end+1} = "O"; err.expected{end+1} = "E"; - if (issparse (cond)) - err.reason{end+1} = "sparse != non-sparse"; - else - err.reason{end+1} = "non-sparse != sparse"; - endif - elseif (iscomplex (cond) != iscomplex (expected)) - err.index{end+1} = "()"; - err.observed{end+1} = "O"; - err.expected{end+1} = "E"; - if (iscomplex (cond)) - err.reason{end+1} = "complex != real"; - else - err.reason{end+1} = "real != complex"; + err.reason{end+1} = ["Class " class(cond) " != " class(expected)]; + elseif (isnumeric (cond)) + if (issparse (cond) != issparse (expected)) + err.index{end+1} = "()"; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + if (issparse (cond)) + err.reason{end+1} = "sparse != non-sparse"; + else + err.reason{end+1} = "non-sparse != sparse"; + endif + elseif (iscomplex (cond) != iscomplex (expected)) + err.index{end+1} = "()"; + err.observed{end+1} = "O"; + err.expected{end+1} = "E"; + if (iscomplex (cond)) + err.reason{end+1} = "complex != real"; + else + err.reason{end+1} = "real != complex"; + endif endif endif endif - endif - if (isempty (err.index)) - - A = cond; - B = expected; - - ## Check exceptional values. - 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)) = ... - repmat ({"'NA' mismatch"}, length (erridx), 1); - endif - errseen = errvec; - - 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)) = ... - repmat ({"'NaN' mismatch"}, length (erridx), 1); - endif - errseen |= errvec; + if (isempty (err.index)) - 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)) = ... - repmat ({"'Inf' mismatch"}, length (erridx), 1); - endif - errseen |= errvec; + A = cond; + B = expected; - ## Check normal values. - ## Replace exceptional values already checked above by zero. - A_null_real = real (A); - B_null_real = real (B); - 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 = 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); - B_null = complex (B_null_real, B_null_imag); - if (isscalar (tol)) - mtol = tol * ones (size (A)); - else - mtol = tol; - endif - - 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 %.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 %.5g exceeds tol %.5g\n",... - [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n"); - endif - - k = (mtol < 0); - 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); + ## Check exceptional values. + 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); @@ -334,14 +252,64 @@ 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"); + repmat ({"'NA' mismatch"}, length (erridx), 1); + endif + errseen = errvec; + + 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)) = ... + repmat ({"'NaN' mismatch"}, length (erridx), 1); endif - ## Test for relative error - Bdiv = Inf (size (B_null)); - Bdiv(k & (B_null != 0)) = B_null(k & (B_null != 0)); - relerr = abs ((A_null - B_null) ./ abs (Bdiv)); - erridx = find ((relerr > abs (mtol)) & k); + errseen |= errvec; + + 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)) = ... + 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 = 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 = 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); + B_null = complex (B_null_real, B_null_imag); + if (isscalar (tol)) + mtol = tol * ones (size (A)); + else + mtol = tol; + endif + + k = (mtol == 0); + erridx = find ((A_null != B_null) & k); if (! isempty (erridx)) err.index(end+1:end+length (erridx)) = ... ind2tuple (size (A), erridx); @@ -350,26 +318,74 @@ 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"); + 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 %.5g exceeds tol %.5g\n",... + [abs(A_null(erridx) - B_null(erridx))(:) mtol(erridx)(:)]')), "\n"); + endif + + k = (mtol < 0); + 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 %.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)); + Bdiv(k & (B_null != 0)) = B_null(k & (B_null != 0)); + 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 %.5g exceeds tol %.5g\n", + [relerr(erridx)(:) -mtol(erridx)(:)]')), "\n"); + endif endif endif + + endif + + ## Print any errors + if (! isempty (err.index)) + argin = ["(" strjoin(cellstr (argn), ",") ")"]; + if (! isempty (errmsg)) + errmsg = [errmsg "\n"]; + endif + errmsg = [errmsg, pprint(argin, err)]; endif endif - ## Print any errors - if (! isempty (err.index)) - argin = ["(" strjoin(cellstr (argn), ",") ")"]; - if (! isempty (errmsg)) - errmsg = [errmsg "\n"]; - endif - errmsg = [errmsg, pprint(argin, err)]; - endif - - endif - - call_depth--; + unwind_protect_cleanup + call_depth--; + end_unwind_protect if (call_depth == -1) ## Last time through. If there were any errors on any pass, raise a flag. @@ -531,6 +547,12 @@ %! y{1}{1}{1} = 3; %! fail ("assert (x,y)", "Abs err 2 exceeds tol 0"); +## function handles +%!assert (@sin, @sin) +%!error assert (@sin, @cos) +%!error assert (pi, @cos) +%!error assert (@sin, pi) + %!test %! x = {[3], [1,2,3]; 100+100*eps, "dog"}; %! y = x;