changeset 33232:c5dc54712378

update help function tests * test/help/cdefdir/cdef_help3.m, test/help/cdefdir/cdef_help4.m, test/help/undoc_fcn.m: New files. * test/help/cdefdir/cdef_help1.m: Rename from test/bug-65220/cdefdir/cdef_help1.m. * test/help/cdefdir/cdef_help2.m: Rename from test/bug-65220/cdefdir/cdef_help2.m. * test/help/help.tst: Rename from test/bug-65220/bug-65220.tst. New tests. Split tests so there is one assert for each test so that it is easier to find an individual failing test. * test/help/module.mk: Rename from test/bug-65220/module.mk. Update. * test/Makefile.am: Update.
author John W. Eaton <jwe@octave.org>
date Thu, 21 Mar 2024 11:21:04 -0400
parents 92ca2f6c6b85
children a0ea07a4c043
files test/Makefile.am test/bug-65220/bug-65220.tst test/bug-65220/cdefdir/cdef_help1.m test/bug-65220/cdefdir/cdef_help2.m test/bug-65220/module.mk test/help/cdefdir/cdef_help1.m test/help/cdefdir/cdef_help2.m test/help/cdefdir/cdef_help3.m test/help/cdefdir/cdef_help4.m test/help/help.tst test/help/module.mk test/help/undoc_fcn.m
diffstat 12 files changed, 525 insertions(+), 304 deletions(-) [+]
line wrap: on
line diff
--- a/test/Makefile.am	Thu Mar 21 10:40:31 2024 -0400
+++ b/test/Makefile.am	Thu Mar 21 11:21:04 2024 -0400
@@ -114,7 +114,6 @@
 include bug-61191/module.mk
 include bug-63841/module.mk
 include bug-65037/module.mk
-include bug-65220/module.mk
 include class-concat/module.mk
 include classdef/module.mk
 include classdef-debug/module.mk
@@ -124,6 +123,7 @@
 include ctor-vs-method/module.mk
 include fcn-handle/module.mk
 include file-encoding/module.mk
+include help/module.mk
 include json/module.mk
 include jupyter-notebook/module.mk
 include load-path/module.mk
--- a/test/bug-65220/bug-65220.tst	Thu Mar 21 10:40:31 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2024 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-%!test <*65220>
-%! unwind_protect
-%!   addpath ('cdefdir');
-%!
-%!   ## Check methods first (bug was disguised if class checked first)
-%!   s = help ('cdef_help1.meth1');
-%!   assert (regexp (s, 'meth1: method help text ABOVE function'));
-%!
-%!   s = help ('cdef_help1.meth2');
-%!   assert (regexp (s, 'meth2: method help text BELOW function'));
-%!
-%!   s = help ('cdef_help1.meth3');
-%!   assert (regexp (s, 'meth3: method help text BELOW function'));
-%!
-%!   s = '';
-%!   try
-%!     s = help ('cdef_help1.meth4');
-%!   catch
-%!     assert (regexp (lasterr (), "'cdef_help1.meth4' is not documented"));
-%!   end_try_catch
-%!   if (! isempty (s))
-%!     error ("Impossible state: Help text found for 'cdef_help1.meth4'");
-%!   endif
-%!
-%!   ## Check documentation for entire class
-%!   s = help ('cdef_help1');
-%!   assert (regexp (s, 'class cdef_help1 : class help text ABOVE classdef'));
-%!
-%!   ## Check documentation for constructor
-%!   s = help ('cdef_help1.cdef_help1');
-%!   assert (regexp (s, 'cdef_help1: constructor help text BELOW function'));
-%!
-%!   ## Check documentation for properties
-%!   s = help ('cdef_help1.prop1');
-%!   assert (regexp (s, 'prop1: property help text ABOVE property'));
-%!
-%!   s = help ('cdef_help1.prop2');
-%!   assert (regexp (s, 'prop2: property help text in EOL-comment'));
-%!
-%! unwind_protect_cleanup
-%!   rmpath ('cdefdir');
-%! end_unwind_protect
-
-%!test <*65220>
-%! unwind_protect
-%!   addpath ('cdefdir');
-%!
-%!   ## Check methods first (bug was disguised if class checked first)
-%!   s = help ('cdef_help2.meth1');
-%!   assert (regexp (s, 'meth1: method help text ABOVE function'));
-%!
-%!   s = help ('cdef_help2.meth2');
-%!   assert (regexp (s, 'meth2: method help text BELOW function'));
-%!
-%!   s = help ('cdef_help2.meth3');
-%!   assert (regexp (s, 'meth3: method help text ABOVE function'));
-%!
-%!   s = '';
-%!   try
-%!     s = help ('cdef_help2.meth4');
-%!   catch
-%!     assert (regexp (lasterr (), "'cdef_help2.meth4' is not documented"));
-%!   end_try_catch
-%!   if (! isempty (s))
-%!     error ("Impossible state: Help text found for 'cdef_help2.meth4'");
-%!   endif
-%!
-%!   ## Check documentation for entire class
-%!   s = help ('cdef_help2');
-%!   assert (regexp (s, 'class cdef_help2 : class help text BELOW classdef'));
-%!
-%!   ## Check documentation for constructor
-%!   s = help ('cdef_help2.cdef_help2');
-%!   assert (regexp (s, 'cdef_help2: constructor help text ABOVE function'));
-%!
-%!   ## Check documentation for properties
-%!   s = help ('cdef_help2.prop1');
-%!   assert (regexp (s, 'prop1: property help text ABOVE property'));
-%!
-%!   s = help ('cdef_help2.prop2');
-%!   assert (regexp (s, 'prop2: property help text in EOL-comment'));
-%!
-%! unwind_protect_cleanup
-%!   rmpath ('cdefdir');
-%! end_unwind_protect
--- a/test/bug-65220/cdefdir/cdef_help1.m	Thu Mar 21 10:40:31 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
-%% Copyright (C) 2024 The Octave Project Developers
-%%
-%% See the file COPYRIGHT.md in the top-level directory of this
-%% distribution or <https://octave.org/copyright/>.
-%%
-%% This file is part of Octave.
-%%
-%% Octave is free software: you can redistribute it and/or modify it
-%% under the terms of the GNU General Public License as published by
-%% the Free Software Foundation, either version 3 of the License, or
-%% (at your option) any later version.
-%%
-%% Octave is distributed in the hope that it will be useful, but
-%% WITHOUT ANY WARRANTY; without even the implied warranty of
-%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-%% GNU General Public License for more details.
-%%
-%% You should have received a copy of the GNU General Public License
-%% along with Octave; see the file COPYING.  If not, see
-%% <https://www.gnu.org/licenses/>.
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-% class cdef_help1 : class help text ABOVE classdef keyword.
-%
-% Type 'help cdef_help1'
-
-classdef cdef_help1
-  % -*- texinfo -*-
-  % class cdef_help1 : class help text BELOW classdef keyword.
-  %
-  % Type 'help cdef_help1'
-
-  properties
-    % prop1: property help text ABOVE property name.
-    % Type "help cdef_help1.prop1"
-    prop1   % prop1: EOL-comment text.  Should not be displayed
-    prop2   % prop2: property help text in EOL-comment for property PROP2.  Type "help cdef_help1.prop2"
-  end
-
-  methods
-
-    % cdef_help1: constructor help text ABOVE function keyword
-    % Type 'help cdef_help1.cdef_help1'.
-    function obj = cdef_help1 (p1, p2)
-      % cdef_help1: constructor help text BELOW function keyword
-      % Type 'help cdef_help1.cdef_help1'.
-      if (nargin ~= 2)
-        obj.prop1 = 'default';
-        obj.prop2 = 42;
-      else
-        obj.prop1 = p1;
-        obj.prop2 = p2;
-      end
-    end
-
-    % meth1: method help text ABOVE function
-    %
-    % Type 'help cdef_help1.meth1'.
-    function obj2 = meth1 (obj, n)
-      obj2 = n + obj;
-    end
-
-    function obj2 = meth2 (obj, n)
-
-      % meth2: method help text BELOW function
-      % The blank line between function and comment is intentional.
-      % Type 'help cdef_help1.meth2'.
-      obj2 = n - obj;
-    end
-
-    % meth3: method help text ABOVE function
-    % Type 'help cdef_help1.meth3'.
-    % This should not be shown.
-    function obj3 = meth3 (obj, n)
-      % meth3: method help text BELOW function
-      % Type 'help cdef_help1.meth3'.
-      % This should be displayed.
-      obj3 = obj + n;
-    end
-
-    function obj4 = meth4 (obj, n)
-
-      obj4 = n - obj;
-      if (n)
-        % meth4: pure comment text.  This should *never* be displayed.
-        % Type 'help cdef_help1.meth4'.
-      end
-    end
-
-  end
-
-end
--- a/test/bug-65220/cdefdir/cdef_help2.m	Thu Mar 21 10:40:31 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-########################################################################
-##
-## Copyright (C) 2024 The Octave Project Developers
-##
-## See the file COPYRIGHT.md in the top-level directory of this
-## distribution or <https://octave.org/copyright/>.
-##
-## This file is part of Octave.
-##
-## Octave is free software: you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation, either version 3 of the License, or
-## (at your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <https://www.gnu.org/licenses/>.
-##
-########################################################################
-
-classdef cdef_help2
-  # -*- texinfo -*-
-  # class cdef_help2 : class help text BELOW classdef keyword.
-  #
-  # Type 'help cdef_help2'
-
-  properties
-    # prop1: property help text ABOVE property name.
-    # Type "help cdef_help2.prop1"
-    prop1   # prop1: EOL-comment text.  Should not be displayed
-    prop2   # prop2: property help text in EOL-comment for property PROP2.  Type "help cdef_help2.prop2"
-  end
-
-  methods
-
-    # cdef_help2: constructor help text ABOVE function keyword
-    # Type 'help cdef_help2.cdef_help2'.
-    # This should be shown because Octave comment character '#' is used.
-    function obj = cdef_help2 (p1, p2)
-      # cdef_help2: constructor help text BELOW function keyword
-      # Type 'help cdef_help2.cdef_help2'.
-      if (nargin ~= 2)
-        obj.prop1 = 'default';
-        obj.prop2 = 42;
-      else
-        obj.prop1 = p1;
-        obj.prop2 = p2;
-      end
-    end
-
-    # meth1: method help text ABOVE function
-    #
-    # Type 'help cdef_help2.meth1'.
-    function obj2 = meth1 (obj, n)
-      obj2 = n + obj;
-    end
-
-    function obj2 = meth2 (obj, n)
-
-      # meth2: method help text BELOW function
-      # The blank line between function and comment is intentional.
-      # Type 'help cdef_help2.meth2'.
-      obj2 = n - obj;
-    end
-
-    # meth3: method help text ABOVE function
-    # Type 'help cdef_help2.meth3'.
-    # This should be shown because Octave comment character '#' is used.
-    function obj3 = meth3 (obj, n)
-      # meth3: method help text BELOW function
-      # Type 'help cdef_help2.meth3'.
-      # This should NOT be displayed.
-      obj3 = obj + n;
-    end
-
-    function obj4 = meth4 (obj, n)
-
-      obj4 = n - obj;
-      if (n)
-        # meth4: pure comment text.  This should *never* be displayed.
-        # Type 'help cdef_help2.meth4'.
-      end
-    end
-
-  end
-
-end
--- a/test/bug-65220/module.mk	Thu Mar 21 10:40:31 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-bug_65220_TEST_FILES = \
-  %reldir%/bug-65220.tst \
-  %reldir%/cdefdir/cdef_help1.m \
-  %reldir%/cdefdir/cdef_help2.m
-
-TEST_FILES += $(bug_65220_TEST_FILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/cdefdir/cdef_help1.m	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,95 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% Copyright (C) 2024 The Octave Project Developers
+%%
+%% See the file COPYRIGHT.md in the top-level directory of this
+%% distribution or <https://octave.org/copyright/>.
+%%
+%% This file is part of Octave.
+%%
+%% Octave is free software: you can redistribute it and/or modify it
+%% under the terms of the GNU General Public License as published by
+%% the Free Software Foundation, either version 3 of the License, or
+%% (at your option) any later version.
+%%
+%% Octave is distributed in the hope that it will be useful, but
+%% WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%% GNU General Public License for more details.
+%%
+%% You should have received a copy of the GNU General Public License
+%% along with Octave; see the file COPYING.  If not, see
+%% <https://www.gnu.org/licenses/>.
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% class cdef_help1 : class help text ABOVE classdef keyword.
+%
+% Type 'help cdef_help1'
+
+classdef cdef_help1
+  % -*- texinfo -*-
+  % class cdef_help1 : class help text BELOW classdef keyword.
+  %
+  % Type 'help cdef_help1'
+
+  properties
+    % prop1: property help text ABOVE property name.
+    % Type "help cdef_help1.prop1"
+    prop1   % prop1: EOL-comment text.  Should not be displayed
+    prop2   % prop2: property help text in EOL-comment for property PROP2.  Type "help cdef_help1.prop2"
+  end
+
+  methods
+
+    % cdef_help1: constructor help text ABOVE function keyword
+    % Type 'help cdef_help1.cdef_help1'.
+    function obj = cdef_help1 (p1, p2)
+      % cdef_help1: constructor help text BELOW function keyword
+      % Type 'help cdef_help1.cdef_help1'.
+      if (nargin ~= 2)
+        obj.prop1 = 'default';
+        obj.prop2 = 42;
+      else
+        obj.prop1 = p1;
+        obj.prop2 = p2;
+      end
+    end
+
+    % meth1: method help text ABOVE function
+    %
+    % Type 'help cdef_help1.meth1'.
+    function obj2 = meth1 (obj, n)
+      obj2 = n + obj;
+    end
+
+    function obj2 = meth2 (obj, n)
+
+      % meth2: method help text BELOW function
+      % The blank line between function and comment is intentional.
+      % Type 'help cdef_help1.meth2'.
+      obj2 = n - obj;
+    end
+
+    % meth3: method help text ABOVE function
+    % Type 'help cdef_help1.meth3'.
+    % This should not be shown.
+    function obj3 = meth3 (obj, n)
+      % meth3: method help text BELOW function
+      % Type 'help cdef_help1.meth3'.
+      % This should be displayed.
+      obj3 = obj + n;
+    end
+
+    function obj4 = meth4 (obj, n)
+
+      obj4 = n - obj;
+      if (n)
+        % meth4: pure comment text.  This should *never* be displayed.
+        % Type 'help cdef_help1.meth4'.
+      end
+    end
+
+  end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/cdefdir/cdef_help2.m	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,92 @@
+########################################################################
+##
+## Copyright (C) 2024 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+classdef cdef_help2
+  # -*- texinfo -*-
+  # class cdef_help2 : class help text BELOW classdef keyword.
+  #
+  # Type 'help cdef_help2'
+
+  properties
+    # prop1: property help text ABOVE property name.
+    # Type "help cdef_help2.prop1"
+    prop1   # prop1: EOL-comment text.  Should not be displayed
+    prop2   # prop2: property help text in EOL-comment for property PROP2.  Type "help cdef_help2.prop2"
+  end
+
+  methods
+
+    # cdef_help2: constructor help text ABOVE function keyword
+    # Type 'help cdef_help2.cdef_help2'.
+    # This should be shown because Octave comment character '#' is used.
+    function obj = cdef_help2 (p1, p2)
+      # cdef_help2: constructor help text BELOW function keyword
+      # Type 'help cdef_help2.cdef_help2'.
+      if (nargin ~= 2)
+        obj.prop1 = 'default';
+        obj.prop2 = 42;
+      else
+        obj.prop1 = p1;
+        obj.prop2 = p2;
+      end
+    end
+
+    # meth1: method help text ABOVE function
+    #
+    # Type 'help cdef_help2.meth1'.
+    function obj2 = meth1 (obj, n)
+      obj2 = n + obj;
+    end
+
+    function obj2 = meth2 (obj, n)
+
+      # meth2: method help text BELOW function
+      # The blank line between function and comment is intentional.
+      # Type 'help cdef_help2.meth2'.
+      obj2 = n - obj;
+    end
+
+    # meth3: method help text ABOVE function
+    # Type 'help cdef_help2.meth3'.
+    # This should be shown because Octave comment character '#' is used.
+    function obj3 = meth3 (obj, n)
+      # meth3: method help text BELOW function
+      # Type 'help cdef_help2.meth3'.
+      # This should NOT be displayed.
+      obj3 = obj + n;
+    end
+
+    function obj4 = meth4 (obj, n)
+
+      obj4 = n - obj;
+      if (n)
+        # meth4: pure comment text.  This should *never* be displayed.
+        # Type 'help cdef_help2.meth4'.
+      end
+    end
+
+  end
+
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/cdefdir/cdef_help3.m	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,38 @@
+########################################################################
+##
+## Copyright (C) 2024 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+classdef cdef_help3
+  properties
+    prop1 = 13;
+    prop2 = 42;
+  end
+
+  methods
+    function obj = cdef_help3 (p1, p2)
+      obj.prop1 = p1;
+      obj.prop2 = p2;
+    end
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/cdefdir/cdef_help4.m	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,31 @@
+########################################################################
+##
+## Copyright (C) 2024 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+classdef cdef_help4
+  properties
+    prop1 = 13;
+    prop2 = 42;
+  end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/help.tst	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,254 @@
+########################################################################
+##
+## Copyright (C) 2024 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check methods first (bug was disguised if class checked first)
+%!   s = help ('cdef_help1.meth1');
+%!   assert (regexp (s, 'meth1: method help text ABOVE function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help1.meth2');
+%!   assert (regexp (s, 'meth2: method help text BELOW function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help1.meth3');
+%!   assert (regexp (s, 'meth3: method help text BELOW function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65258>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help1.meth4');
+%!   assert (regexp (s, 'undocumented method: obj4 = meth4 \(obj, n\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for entire class
+%!   s = help ('cdef_help1');
+%!   assert (regexp (s, 'class cdef_help1 : class help text ABOVE classdef'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for constructor
+%!   s = help ('cdef_help1.cdef_help1');
+%!   assert (regexp (s, 'cdef_help1: constructor help text BELOW function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for properties
+%!   s = help ('cdef_help1.prop1');
+%!   assert (regexp (s, 'prop1: property help text ABOVE property'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help1.prop2');
+%!   assert (regexp (s, 'prop2: property help text in EOL-comment'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check methods first (bug was disguised if class checked first)
+%!   s = help ('cdef_help2.meth1');
+%!   assert (regexp (s, 'meth1: method help text ABOVE function'));
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help2.meth2');
+%!   assert (regexp (s, 'meth2: method help text BELOW function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help2.meth3');
+%!   assert (regexp (s, 'meth3: method help text ABOVE function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help2.meth4');
+%!   assert (regexp (s, 'undocumented method: obj4 = meth4 \(obj, n\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for entire class
+%!   s = help ('cdef_help2');
+%!   assert (regexp (s, 'class cdef_help2 : class help text BELOW classdef'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for constructor
+%!   s = help ('cdef_help2.cdef_help2');
+%!   assert (regexp (s, 'cdef_help2: constructor help text ABOVE function'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   ## Check documentation for properties
+%!   s = help ('cdef_help2.prop1');
+%!   assert (regexp (s, 'prop1: property help text ABOVE property'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65220>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help2.prop2');
+%!   assert (regexp (s, 'prop2: property help text in EOL-comment'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65258>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help3');
+%!   assert (regexp (s, 'undocumented constructor: obj = cdef_help3 \(p1, p2\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65258>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help3.cdef_help3');
+%!   assert (regexp (s, 'undocumented constructor: obj = cdef_help3 \(p1, p2\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65258>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help4');
+%!   assert (regexp (s, 'default constructor: obj = cdef_help4 \(\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!test <*65258>
+%! unwind_protect
+%!   addpath ('cdefdir');
+%!
+%!   s = help ('cdef_help4.cdef_help4');
+%!   assert (regexp (s, 'default constructor: obj = cdef_help4 \(\)'));
+%!
+%! unwind_protect_cleanup
+%!   rmpath ('cdefdir');
+%! end_unwind_protect
+
+%!assert <*65258> (regexp (help ('undoc_fcn'), 'undocumented function: \[x, y, z\] = undoc_fcn \(a, b, ~, c = 3\)'))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/module.mk	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,9 @@
+help_TEST_FILES = \
+  %reldir%/help.tst \
+  %reldir%/undoc_fcn.m \
+  %reldir%/cdefdir/cdef_help1.m \
+  %reldir%/cdefdir/cdef_help2.m \
+  %reldir%/cdefdir/cdef_help3.m \
+  %reldir%/cdefdir/cdef_help4.m
+
+TEST_FILES += $(help_TEST_FILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/help/undoc_fcn.m	Thu Mar 21 11:21:04 2024 -0400
@@ -0,0 +1,5 @@
+function [x, y, z] = undoc_fcn (a, b, ~, c = 3)
+  x = a;
+  y = b;
+  z = c;
+end