# HG changeset patch
# User Ken Marek <marek_ka@mercer.edu>
# Date 1668658078 18000
#      Wed Nov 16 23:07:58 2022 -0500
# Node ID 680726c51fe2fdca1520e6cd0e4ecdcbd3e07135
# Parent  6ea81caebab0714a67df3a227e77c73222fc0d2d
Add BIST for OutputSel option in ode23, ode23s, ode45 (bug #63229)

* ode23.m, ode23s.m, ode45.m: Add a BIST test function to be called within
odeset to ensure the odeXX function call passes the correct elements to the
output monitoring function. Add BISTs that call test function in scalar and
vector forms.

diff -r 6ea81caebab0 -r 680726c51fe2 scripts/ode/ode23.m
--- a/scripts/ode/ode23.m	Wed Nov 16 16:13:30 2022 -0800
+++ b/scripts/ode/ode23.m	Wed Nov 16 23:07:58 2022 -0500
@@ -365,6 +365,35 @@
 %!    error ("fout: invalid flag <%s>", flag);
 %!  endif
 %!endfunction
+%!function stop_solve = OutputSel_test (t, y, flag, x)
+%!  ## x == 1: select y(1)
+%!  ## x == 2: select y(2)
+%!  ## x == 3: select y([1,2])
+%!  persistent y_last
+%!  if strcmp (flag, "init")
+%!    y_last = y;
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (y) == 1);
+%!    elseif (x == 3)
+%!      assert (length (y) == 2);
+%!    endif
+%!  elseif strcmp (flag, "done")
+%!    y_exp = fref ().';
+%!    if (x < 3)
+%!      assert (y_last, y_exp(x), 5e-4);
+%!    else
+%!      assert (y_last, y_exp, 5e-4);
+%!    endif
+%!  else # flag == ""
+%!    y_last = y(:, end);
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (t) == length (y));
+%!    else
+%!      assert (2 * length (t) == length (y(:)));
+%!    endif
+%!  endif
+%!  stop_solve = 0;
+%!endfunction
 %!
 %!test  # two output arguments
 %! [t, y] = ode23 (@fpol, [0 2], [2 0]);
@@ -442,8 +471,17 @@
 %! opt = odeset ("NonNegative", 2);
 %! sol = ode23 (@fpol, [0 2], [2 0], opt);
 %! assert ([sol.x(end); sol.y(:,end)], [2; 2; 0], 1e-1);
-%!test  # Details of OutputSel can't be tested
-%! opt = odeset ("OutputFcn", @fout, "OutputSel", 1);
+%!test  # OutputSel 1 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 1), ...
+%!               "OutputSel", 1);
+%! sol = ode23 (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel 2 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 2), ...
+%!               "OutputSel", 2);
+%! sol = ode23 (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel [1,2] (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 3), ...
+%!               "OutputSel", [1, 2]);
 %! sol = ode23 (@fpol, [0 2], [2 0], opt);
 %!test  # Stats must add further elements in sol
 %! opt = odeset ("Stats", "on");
diff -r 6ea81caebab0 -r 680726c51fe2 scripts/ode/ode23s.m
--- a/scripts/ode/ode23s.m	Wed Nov 16 16:13:30 2022 -0800
+++ b/scripts/ode/ode23s.m	Wed Nov 16 23:07:58 2022 -0500
@@ -399,6 +399,35 @@
 %!    error ("fout: invalid flag <%s>", flag);
 %!  endif
 %!endfunction
+%!function stop_solve = OutputSel_test (t, y, flag, x)
+%!  ## x == 1: select y(1)
+%!  ## x == 2: select y(2)
+%!  ## x == 3: select y([1,2])
+%!  persistent y_last
+%!  if strcmp (flag, "init")
+%!    y_last = y;
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (y) == 1);
+%!    elseif (x == 3)
+%!      assert (length (y) == 2);
+%!    endif
+%!  elseif strcmp (flag, "done")
+%!    y_exp = fref ().';
+%!    if (x < 3)
+%!      assert (y_last, y_exp(x), 1e-4);
+%!    else
+%!      assert (y_last, y_exp, 1e-4);
+%!    endif
+%!  else # flag == ""
+%!    y_last = y(:,end);
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (t) == length (y));
+%!    else
+%!      assert (2 * length (t) == length (y(:)));
+%!    endif
+%!  endif
+%!  stop_solve = 0;
+%!endfunction
 %!
 %!test  # two output arguments
 %! [t, y] = ode23s (@fpol, [0 2], [2 0]);
@@ -442,8 +471,17 @@
 %! opt = odeset ("RelTol", 1e-8, "NormControl", "on");
 %! sol = ode23s (@fpol, [0 2], [2 0], opt);
 %! assert ([sol.x(end); sol.y(:,end)], [2; fref'], 1e-4);
-%!test  # Details of OutputSel can't be tested
-%! opt = odeset ("OutputFcn", @fout, "OutputSel", 1);
+%!test  # OutputSel 1 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 1), ...
+%!               "OutputSel", 1);
+%! sol = ode23s (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel 2 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 2), ...
+%!               "OutputSel", 2);
+%! sol = ode23s (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel [1,2] (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 3), ...
+%!               "OutputSel", [1, 2]);
 %! sol = ode23s (@fpol, [0 2], [2 0], opt);
 %!test  # Stats must add further elements in sol
 %! opt = odeset ("Stats", "on");
diff -r 6ea81caebab0 -r 680726c51fe2 scripts/ode/ode45.m
--- a/scripts/ode/ode45.m	Wed Nov 16 16:13:30 2022 -0800
+++ b/scripts/ode/ode45.m	Wed Nov 16 23:07:58 2022 -0500
@@ -364,6 +364,35 @@
 %!    error ("fout: invalid flag <%s>", flag);
 %!  endif
 %!endfunction
+%!function stop_solve = OutputSel_test (t, y, flag, x)
+%!  ## x == 1: select y(1)
+%!  ## x == 2: select y(2)
+%!  ## x == 3: select y([1,2])
+%!  persistent y_last
+%!  if strcmp (flag, "init")
+%!    y_last = y;
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (y) == 1);
+%!    elseif (x == 3)
+%!      assert (length (y) == 2);
+%!    endif
+%!  elseif strcmp (flag, "done")
+%!    y_exp = fref ().';
+%!    if (x < 3)
+%!      assert (y_last, y_exp(x), 1e-4);
+%!    else
+%!      assert (y_last, y_exp, 1e-4);
+%!    endif
+%!  else # flag == ""
+%!    y_last = y(:,end);
+%!    if ((x == 1) || (x == 2))
+%!      assert (length (t) == length (y));
+%!    else
+%!      assert (2 * length (t) == length (y(:)));
+%!    endif
+%!  endif
+%!  stop_solve = 0;
+%!endfunction
 %!
 %!test  # two output arguments
 %! [t, y] = ode45 (@fpol, [0 2], [2 0]);
@@ -453,8 +482,17 @@
 %! opt = odeset ("NonNegative", 2);
 %! sol = ode45 (@fpol, [0 2], [2 0], opt);
 %! assert ([sol.x(end); sol.y(:,end)], [2; 2; 0], 0.5);
-%!test  # Details of OutputSel can't be tested
-%! opt = odeset ("OutputFcn", @fout, "OutputSel", 1);
+%!test  # OutputSel 1 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 1), ...
+%!               "OutputSel", 1);
+%! sol = ode45 (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel 2 (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 2), ...
+%!               "OutputSel", 2);
+%! sol = ode45 (@fpol, [0 2], [2 0], opt);
+%!test  # OutputSel [1,2] (see function OutputSel_test for asserts)
+%! opt = odeset ("OutputFcn", @(t, y, flag) OutputSel_test (t, y, flag, 3), ...
+%!               "OutputSel", [1,2]);
 %! sol = ode45 (@fpol, [0 2], [2 0], opt);
 %!test  # Stats must add further elements in sol
 %! opt = odeset ("Stats", "on");
