doctest-0.8.0/0000755000000000000000000000000014354676362010072 5ustar doctest-0.8.0/CONTRIBUTORS0000644000000000000000000000034414354676362011753 0ustar Authors and Contributors ======================== Thomas Smith Michael Walter Colin B. Macdonald Oliver Heimlich Mike Miller Andrew Janke Manuel Leonhardt (Please contact the developers if your name should be here but isn't!) doctest-0.8.0/COPYING0000644000000000000000000000304614354676362011130 0ustar Copyright (c) 2010 Thomas Grenfell Smith Copyright (c) 2011, 2013-2015 Michael Walter Copyright (c) 2015 Colin B. Macdonald All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. doctest-0.8.0/DESCRIPTION0000644000000000000000000000111714354676362011600 0ustar Name: doctest Version: 0.8.0 Date: 2023-01-03 Author: various authors Maintainer: Colin B. Macdonald , Michael Walter Title: Documentation tests Description: Find and run example code within documentation. Formatted blocks of example code are extracted from documentation files and executed to confirm their output is correct. This can be part of a testing framework or simply to ensure that documentation stays up-to-date during software development. Depends: octave (>= 4.2.0) Url: https://octave.sourceforge.io/doctest License: BSD-3-Clause doctest-0.8.0/INDEX0000644000000000000000000000006014354676362010660 0ustar doctest >> Documentation tests testing doctest doctest-0.8.0/Makefile0000644000000000000000000001220014354676362011525 0ustar SHELL := /bin/bash # Maintainer makefile for Octave Doctest # # SPDX-License-Identifier: FSFAP # # Copyright 2015 Oliver Heimlich # Copyright 2015 Michael Walter # Copyright 2015-2017, 2019, 2022 Colin B. Macdonald # Copyright 2016 Carnë Draug # Copyright 2019 Mike Miller # Copyright 2019 Andrew Janke # Copyright 2019 Manuel Leonhardt # Copyright 2022 Markus Muetzel # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. This file is offered as-is, # without any warranty. TAR := $(shell which gtar 2>/dev/null || echo tar) PACKAGE := $(shell grep "^Name: " DESCRIPTION | cut -f2 -d" ") VERSION := $(shell grep "^Version: " DESCRIPTION | cut -f2 -d" ") BUILD_DIR := tmp MATLAB_PKG := ${BUILD_DIR}/${PACKAGE}-matlab-${VERSION} MATLAB_PKG_ZIP := ${MATLAB_PKG}.zip OCTAVE_RELEASE := ${BUILD_DIR}/${PACKAGE}-${VERSION} OCTAVE_RELEASE_TARBALL := ${BUILD_DIR}/${PACKAGE}-${VERSION}.tar.gz INSTALLED_PACKAGE := ~/octave/${PACKAGE}-${VERSION}/packinfo/DESCRIPTION HTML_DIR := ${BUILD_DIR}/${PACKAGE}-html HTML_TARBALL := ${HTML_DIR}.tar.gz OCTAVE ?= octave MKOCTFILE ?= mkoctfile -Wall MATLAB ?= matlab TEST_CODE=ver(), success = doctest({'doctest', 'test/', 'test/examples/'}); exit(~success); # run tests twice so we can see some output BIST_CODE=ver(), cd('test'); disp(pwd()), test('bist'); success1 = test('bist'); cd('..'); cd('test_extra'); disp(pwd()), test('run_tests'); success2 = test('run_tests'); exit(~success1 || ~success2); MATLAB_EXTRA_TEST_CODE=ver(), addpath(pwd()), disp(pwd()), cd('test_extra'); disp(pwd()), success = run_tests(); exit(~success); .PHONY: help clean install test test-interactive dist html matlab_test matlab_pkg help: @echo Available rules: @echo " clean clean all temporary files" @echo " install install package in Octave" @echo " test run tests with Octave" @echo " test-interactive run tests with Octave in interactive mode" @echo " test-bist run additional tests with Octave" @echo " dist create Octave package (${OCTAVE_RELEASE_TARBALL})" @echo " html create Octave Forge html (${HTML_TARBALL})" @echo " release create both tarballs and md5 sums" @echo @echo " matlab_test run tests with Matlab" @echo " matlab_pkg create Matlab package (${MATLAB_PKG_ZIP})" GIT_DATE := $(shell git show -s --format=\%ci) # Follows the recommendations of https://reproducible-builds.org/docs/archives define create_tarball $(shell set -o pipefail; cd $(dir $(1)) \ && find $(notdir $(1)) -print0 \ | LC_ALL=C sort -z \ | $(TAR) c --mtime="$(GIT_DATE)" \ --owner=root --group=root --numeric-owner \ --no-recursion --null -T - -f - \ | gzip -9n > "$(2)") endef %.tar.gz: % $(call create_tarball,$<,$(notdir $@)) %.zip: % cd "$(BUILD_DIR)" ; zip -9qr - "$(notdir $<)" > "$(notdir $@)" $(OCTAVE_RELEASE): .git/index | $(BUILD_DIR) @echo "Creating package version $(VERSION) release ..." -$(RM) -r "$@" git archive --format=tar --prefix="$@/" HEAD | $(TAR) -x $(RM) "$@/README.matlab.md" \ "$@/.gitignore" \ "$@/.mailmap" $(RM) -r "$@/.github" $(RM) -r "$@/util" chmod -R a+rX,u+w,go-w "$@" $(HTML_DIR): install | $(BUILD_DIR) @echo "Generating HTML documentation. This may take a while ..." -$(RM) -r "$@" $(OCTAVE) --no-window-system --silent \ --eval "pkg load generate_html; " \ --eval "pkg load $(PACKAGE);" \ --eval "options = get_html_options ('octave-forge');" \ --eval "generate_package_html ('${PACKAGE}', '${HTML_DIR}', options)" chmod -R a+rX,u+w,go-w $@ dist: $(OCTAVE_RELEASE_TARBALL) html: $(HTML_TARBALL) md5: $(OCTAVE_RELEASE_TARBALL) $(HTML_TARBALL) @md5sum $^ release: md5 @echo "Upload @ https://sourceforge.net/p/octave/package-releases/new/" @echo "*After review*, an Octave-Forge admin will tag this with:" @echo " git tag -a v$(VERSION) -m \"Version $(VERSION)\"" # TODO: more matlab subdirs ${BUILD_DIR} ${MATLAB_PKG}/private: mkdir -p "$@" clean: rm -rf "${BUILD_DIR}" test: ${OCTAVE} --path ${CURDIR}/inst --eval "${TEST_CODE}" test-interactive: script --quiet --command "${OCTAVE} --path ${CURDIR}/inst --eval \"${TEST_CODE}\"" /dev/null test-bist: ${OCTAVE} --path ${CURDIR}/inst --eval "${BIST_CODE}" ## Install in Octave (locally) install: ${INSTALLED_PACKAGE} ${INSTALLED_PACKAGE}: ${OCTAVE_RELEASE_TARBALL} $(OCTAVE) --silent --eval "pkg install $<" ## Matlab packaging matlab_pkg: $(MATLAB_PKG_ZIP) ${MATLAB_PKG}: | $(BUILD_DIR) ${MATLAB_PKG}/private $(OCTAVE) --path ${CURDIR}/util --silent --eval \ "convert_comments('inst/', '', '../${MATLAB_PKG}/')" cp -a inst/private/*.m ${MATLAB_PKG}/private/ cp -a COPYING ${MATLAB_PKG}/ cp -a CONTRIBUTORS ${MATLAB_PKG}/ cp -a NEWS ${MATLAB_PKG}/ cp -a README.matlab.md ${MATLAB_PKG}/ cp -a test ${MATLAB_PKG}/ cp -a test_extra ${MATLAB_PKG}/ matlab_test: matlab_pkg cd "${MATLAB_PKG}"; ${MATLAB} -nojvm -nodisplay -nosplash -r "${TEST_CODE}" matlab_extra_test: matlab_pkg cd "${MATLAB_PKG}"; ${MATLAB} -nojvm -nodisplay -nosplash -r "${MATLAB_EXTRA_TEST_CODE}" doctest-0.8.0/NEWS0000644000000000000000000001063214354676362010573 0ustar doctest 0.8.0 (2023-01-03) ========================== * Expected error messages can be optionally prefixed with "error: ". * Writing "??? " at the beginning of an error is now deprecated. * Texinfo users can markup errors with `@error{}`. * `doctest myclass` has been refactored with various bugs fixed. * Preliminary support for `doctest classdef.method` on Octave. * Test classdef methods using dotted `classdef.method` while still using `@class/method` on old-style classes. * Functions defined directly in the Octave interpreter can now be tested. * Test suite fixes for Octave 6 and 7. * Source code is encoded with UTF-8, indicated with `.oct-config` files. * Don't doctest some classdef methods twice. doctest 0.7.0 (2019-03-23) ========================== * Functions within compiled `.oct` files can now be tested. * Tests are run with default number formatting (see `help doctest`). * More robust to errors during testing. * Makefile improvements and fixes. doctest 0.6.1 (2018-01-04) ========================== * Workaround regex bug on ARM (again!). doctest 0.6.0 (2017-12-25) ========================== * Tests can now call "clear" and "clear all". * Fixes for running on Octave development versions (upcoming 4.4.0). * Minimum supported Octave version is now 4.2.0. The package no longer has any compiled code and does not include an "evalc" implementation. doctest 0.5.0 (2016-11-13) ========================== * SKIP_IF and other conditional directives can include small single-line blocks of code. For example: - "% doctest: +SKIP_IF(foo() && bar(42))" * Recursion into subdirectories is now the default; pass "-nonrecursive" for the previous default behaviour. * In Texinfo mode, skip tests without output by default. This is an experimental change to help test the GNU Octave project; the feature might disappear without warning in a future version. * Workaround regex bug on ARM architecture. * Minimum supported Octave version is now 4.0.0. doctest 0.4.1 (2016-01-04) ========================== * Added conditional variants of SKIP and XFAIL directives to control test execution based on runtime conditions: - "% doctest: +SKIP_IF(condition)" - "% doctest: +SKIP_UNLESS(condition)" - "% doctest: +XFAIL_IF(condition)" - "% doctest: +XFAIL_UNLESS(condition)" * Added constants DOCTEST_OCTAVE and DOCTEST_MATLAB that can be used as conditions in SKIP_IF etc. * Improved handling of example code in TexInfo documentation. - Added support for @print{} macros, which may be used for output that is not part of a returned value. - Examples without ">>" markers use code indentation together with @result{} / @print{} macros to classify input and output lines in a natural way. It is no longer necessary to split code into several @example / @group blocks. - Allow arbitrary TexInfo macros. The documentation is interpreted by makeinfo before running the code examples. - Fixed handling of TexInfo files with Windows line endings. * Improved folder/directory traversals: - Ignore hidden (dot) directories. - Ignore files that are neither m-files nor texinfo. doctest 0.4.0 (2015-07-02) ========================== * Change doctest interface to be closer to Octave's test function. * Change wildcard string from '***' to '...'. * Doctests can be influenced with directives: - mark tests to be skipped by appending "% doctest: +SKIP". - mark tests expected to fail with "% doctest: +XFAIL". - stricter whitespace matching: "% doctest: -NORMALIZE_WHITESPACE". - disable "..." wildcard matching with "% doctest: -ELLIPSIS". * Support "doctest foldername" to run tests on the files/classes within the folder/directory "foldername". With optional recursion. * Improve evalc implementation on Octave. * Other bug fixes. doctest 0.3.0 (2015-05-12) ========================== * Multiline input now works (e.g., a matrix split across lines). * Allow "ans = " to be omitted. * Pure texinfo files can be tested: "doctest myfile.texinfo". * Other bug fixes. * Support and directory structure for being an Octave package. doctest 0.2.0 (2015-04-06) ========================== * Octave support, including examples in Texinfo blocks. * Return the number of tests and number failed. doctest-0.8.0/README.md0000644000000000000000000000247214354676362011356 0ustar Doctest ======= The [Octave-Forge Doctest](http://octave.sourceforge.net/doctest/) package finds specially-formatted blocks of example code within documentation files. It then executes the code and confirms the output is correct. This can be useful as part of a testing framework or simply to ensure that documentation stays up-to-date during software development. To get started, here is a simple example: ~~~matlab function greet(user) % Returns a greeting. % % >> greet World % % Hello, World! disp(['Hello, ' user '!']); end ~~~ We can test it by invoking `doctest greet` at the Octave prompt, which will give the following output: ~~~ greet .................................................. PASS 1/1 Summary: PASS 1/1 1/1 targets passed, 0 without tests. ~~~ Doctest also supports Texinfo markup, which is [popular](https://www.gnu.org/software/octave/doc/interpreter/Documentation-Tips.html) in the Octave world, and it provides various toggles and switches for customizing its behavior. The [Doctest documentation](https://octave.sourceforge.io/doctest/function/doctest.html) contains information on all this. Quite appropriately, Doctest can test its own documentation. We also maintain a [list of software](https://github.com/catch22/octave-doctest/wiki/WhoIsUsingDoctest) that is using Doctest. doctest-0.8.0/inst/0000755000000000000000000000000014354676362011047 5ustar doctest-0.8.0/inst/.oct-config0000644000000000000000000000001714354676362013076 0ustar encoding=utf-8 doctest-0.8.0/inst/doctest.m0000644000000000000000000002772214354676362012704 0ustar %% Copyright (c) 2010 Thomas Grenfell Smith %% Copyright (c) 2011, 2013-2016 Michael Walter %% Copyright (c) 2015-2019, 2023 Colin B. Macdonald %% Copyright (c) 2019 Manuel Leonhardt %% SPDX-License-Identifier: BSD-3-Clause %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions are met: %% %% 1. Redistributions of source code must retain the above copyright notice, %% this list of conditions and the following disclaimer. %% %% 2. Redistributions in binary form must reproduce the above copyright notice, %% this list of conditions and the following disclaimer in the documentation %% and/or other materials provided with the distribution. %% %% 3. Neither the name of the copyright holder nor the names of its %% contributors may be used to endorse or promote products derived from this %% software without specific prior written permission. %% %% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" %% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE %% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE %% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE %% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR %% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF %% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN %% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) %% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %% POSSIBILITY OF SUCH DAMAGE. %% -*- texinfo -*- %% @documentencoding UTF-8 %% @deftypefn {} {} doctest @var{target} %% @deftypefnx {} {} doctest @var{target} -nonrecursive %% @deftypefnx {} {@var{success} =} doctest (@var{target}, @dots{}) %% @deftypefnx {} {[@var{numpass}, @var{numtests}, @var{summary}] =} doctest (@dots{}) %% Run examples embedded in documentation. %% %% Doctest finds and runs code found in @var{target}, which can be a: %% @itemize %% @item function; %% @item class; %% @item Texinfo file; %% @item .oct/.mex compiled code; %% @item directory/folder (pass @code{-nonrecursive} to skip subfolders); %% @item cell array of such items. %% @end itemize %% When called with a single return value, return whether all tests have %% succeeded (@var{success}). %% %% When called with two or more return values, return the number of tests %% passed (@var{numpass}), the total number of tests (@var{numtests}) and a %% structure @var{summary} with various fields. %% %% %% Doctest finds example blocks, executes the code and verifies that the %% results match the expected output. For example, running %% @code{doctest doctest} will execute this code: %% %% @example %% @group %% >> 1 + 3 %% ans = %% 4 %% @end group %% @end example %% %% If there's no output, just put the next line right after the one with %% no output. If the line does produce output (for instance, an error), %% this will be recorded as a test failure. %% %% @example %% @group %% >> x = 3 + 4; %% >> x %% x = %% 7 %% @end group %% @end example %% %% %% @strong{Wildcards} %% You can use a wildcard to match unpredictable output: %% %% @example %% @group %% >> disp(datestr(now, 'yyyy-mm-dd')) %% 2... %% @end group %% @end example %% %% @strong{Expecting an error} %% Doctest can deal with errors, to some extent. For instance, this case is %% handled correctly: %% %% @example %% @group %% >> not_a_real_function(42) %% error: ...ndefined ... %% @end group %% @end example %% %% Note use of wildcards here; MATLAB spells this @code{Undefined}, while %% Octave uses @code{undefined}. Writing @code{error: } is optional. %% Currently errors do not work if the code emits other output before the %% error message. Warnings are different; they work fine. %% %% %% @strong{Multiple lines of code} %% Code spanning multiple lines can be entered by prefixing all subsequent %% lines with @code{..}, e.g., %% %% @example %% @group %% >> for i = 1:3 %% .. i %% .. end %% i = 1 %% i = 2 %% i = 3 %% @end group %% @end example %% (But note this is not required when writing texinfo documentation, %% see below). %% %% %% @strong{Shortcuts} %% You can optionally omit @code{ans = } when the output is unassigned. But %% actual variable names (such as @code{x = }) must be included. Leading %% and trailing whitespace on each line of output will be discarded which %% gives some freedom to, e.g., indent the code output as you wish. %% %% %% @strong{Directives} %% You can skip certain tests by marking them with a special comment. This %% can be used, for example, for a test not expected to pass or to avoid %% opening a figure window during automated testing. %% %% @example %% @group %% >> a = 6 % doctest: +SKIP %% b = 42 %% >> plot(...) % doctest: +SKIP %% @end group %% @end example %% %% %% These special comments act as directives for modifying test behaviour. %% You can also mark tests that you expect to fail: %% %% @example %% @group %% >> a = 6 % doctest: +XFAIL %% b = 42 %% @end group %% @end example %% %% Both the @code{+SKIP} and the @code{+XFAIL} directives have conditional %% variants (e.g., @code{+SKIP_IF} and @code{+SKIP_UNLESS}) that control %% test execution and expectations based on runtime conditions, such as %% the platform, operating systems, or installed packages: %% %% @example %% @group %% >> license % doctest: +XFAIL_IF(DOCTEST_MATLAB) %% ans = GNU General Public License %% @end group %% @end example %% %% Doctest provides the default flags @code{DOCTEST_OCTAVE} and %% @code{DOCTEST_MATLAB}, but you can call functions and access arbitrary %% variables (including those defined by previous tests). %% %% %% By default, all adjacent white space is collapsed into a single space %% before comparison. A stricter mode where ``internal whitespace'' must %% match is available: %% %% @example %% @group %% >> fprintf('a b\nc d\n') %% a b %% c d %% %% >> fprintf('a b\nc d\n') % doctest: -NORMALIZE_WHITESPACE %% a b %% c d %% @end group %% @end example %% %% %% To disable the @code{...} wildcard, use the @code{-ELLIPSIS} directive. %% %% %% @strong{Numerical Format} %% Tests are run using default formatting: %% @example %% @group %% >> 6/5 %% ans = 1.2000 %% @end group %% @end example %% %% If your test changes the global state (e.g., @code{format} or %% @code{chdir}), you may need to undo your changes afterwards. %% In this example, we followup with @code{format} to reset to the %% default five digits: %% %% @example %% @group %% >> format long %% >> 355/113 %% ans = 3.14159292035... %% >> format %% @end group %% @end example %% %% %% @strong{Diary Style} %% When the m-file contains plaintext documentation, doctest finds tests %% by searching for lines that begin with @code{>>}. It then finds the %% expected output by searching for the next @code{>>} or two blank lines. %% %% @strong{Octave/Texinfo Style} %% If your m-file contains Texinfo markup, then doctest finds code in %% @code{@@example @dots{} @@end example} blocks. Note: %% @itemize %% @item The two-blank-lines convention is not required. %% @item The use of @code{>>} is neither required nor recommended as Octave %% documentation conventionally indicates output with @code{@@result@{@}} %% and @code{@@print@{@}}. Ambiguities are resolving by assuming output %% is indented further than input. %% @end itemize %% %% A typical Texinfo-style doctest looks like: %% @example %% a = 5; %% b = a + 1 %% @result{} b = 6 %% disp("hello\nthere") %% @print{} hello %% @print{} there %% @end example %% %% The two styles are not mutually exclusive: this documentation is written %% in Texinfo using a hybrid approach. %% %% @strong{Support for non-ASCII characters} %% If you encounter file encoding issues on Octave, @pxref{dir_encoding} and %% @ref{__mfile_encoding__}. For example, this file itself is encoded in %% utf-8 and declares this by installing a @code{.oct-config} file. %% Matlab users might want to try @code{feature('DefaultCharacterSet', 'UTF-8')}. %% %% @seealso{test} %% @end deftypefn function varargout = doctest(targets, varargin) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Process parameters. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if (nargin < 1 || nargout > 3) if (is_octave) print_usage() end help doctest return end % if given a single object, wrap it in a cell array if ~iscell(targets) targets = {targets}; end % input parsing for options and directives recursive = true; if (nargout < 3) verbose = true; else verbose = false; end directives = doctest_default_directives(); for i = 1:(nargin-1) assert(ischar(varargin{i})) pm = varargin{i}(1); directive = varargin{i}(2:end); switch directive case 'recursive' % weakly deprecated, not mentioned in help text assert(strcmp(pm, '-')) recursive = true; case 'nonrecursive' assert(strcmp(pm, '-')) recursive = false; case 'quiet' % currently not mentioned in help text assert(strcmp(pm, '-')) verbose = false; case 'verbose' % currently not mentioned in help text assert(strcmp(pm, '-')) verbose = true; otherwise assert(strcmp(pm, '+') || strcmp(pm, '-')) warning('Doctest:deprecated', ... ['Support for specifying directives on the command line is deprecated\n' ... ' and will be removed in a future version (for discussion, see\n' ... ' https://github.com/catch22/octave-doctest/issues/127).']); enable = strcmp(varargin{i}(1), '+'); directives = doctest_default_directives(directives, directive, enable); end end % for now, always print to stdout fid = 1; % get terminal color codes [color_ok, color_err, color_warn, reset] = doctest_colors(fid); if (verbose) fprintf(fid, 'Doctest v0.8.0: this is Free Software without warranty, see source.\n\n'); end summary = struct(); summary.num_targets = 0; summary.num_targets_passed = 0; summary.num_targets_without_tests = 0; summary.num_targets_with_extraction_errors = 0; summary.num_tests = 0; summary.num_tests_passed = 0; % stash user's formatting if (is_octave) try [save_format, save_spacing] = format(); catch % TODO: remove when we drop support for Octave < 4.4.0 save_format = eval('__formatstring__()'); save_spacing = eval('ifelse(__compactformat__(), "compact", "loose")'); end else save_format = get(0, 'Format'); save_spacing = get(0, 'FormatSpacing'); end % force default formatting format() %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Collect and run tests %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% for i=1:numel(targets) summary = doctest_collect(targets{i}, directives, summary, recursive, verbose, 0, fid); end % restore user's formatting format(save_format) format(save_spacing) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Report summary %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if (verbose) fprintf(fid, '\nSummary:\n\n'); if (summary.num_tests_passed == summary.num_tests) fprintf(fid, [' ' color_ok 'PASS %4d/%-4d' reset '\n\n'], summary.num_tests_passed, summary.num_tests); else fprintf(fid, [' ' color_err 'FAIL %4d/%-4d' reset '\n\n'], summary.num_tests - summary.num_tests_passed, summary.num_tests); end fprintf(fid, '%d/%d targets passed, %d without tests', summary.num_targets_passed, summary.num_targets, summary.num_targets_without_tests); if summary.num_targets_with_extraction_errors > 0 fprintf(fid, [', ' color_err '%d with extraction errors' reset], summary.num_targets_with_extraction_errors); end fprintf(fid, '.\n\n'); end if nargout == 1 varargout = {summary.num_targets_passed == summary.num_targets}; elseif nargout > 1 varargout = {summary.num_tests_passed, summary.num_tests, summary}; end end doctest-0.8.0/inst/private/0000755000000000000000000000000014354676362012521 5ustar doctest-0.8.0/inst/private/doctest_collect.m0000644000000000000000000004535514354676362016065 0ustar function summary = doctest_collect(w, directives, summary, recursive, verbose, depth, fid) %DOCTEST_COLLECT Find and run doctests. % % The input W is the name of a class, directory, function or filename: % * For a directory, calls itself on the contents, recursively if % RECURSIVE is true; % * For a class, all methods are tested; % * When running Octave, it can also be the filename of a Texinfo file. %% % Copyright (c) 2010 Thomas Grenfell Smith % Copyright (c) 2015 Michael Walter % Copyright (c) 2015-2019, 2022 Colin B. Macdonald % Copyright (c) 2015 Oliver Heimlich % Copyright (C) 2018 Mike Miller % SPDX-License-Identifier: BSD-3-Clause % TODO: methods('logical') octave/matlab differ: which behaviour do we want? % TODO: what about builtin "test" versus dir "test/"? Do we prefer dir? if (isempty(w)) return end % determine type of target if is_octave() % Note: ripe for refactoring once "exist(w, 'class')" works in Octave. [~, ~, ext] = fileparts(w); if any(strcmpi(ext, {'.texinfo' '.texi' '.txi' '.tex'})) type = 'texinfo'; elseif (strcmp (ext, '.oct') && exist (w) == 3) % .oct explicitly type = 'octfile'; elseif (exist (w) == 3) % .oct/.mex [~, w, ~] = fileparts (w); % strip extension if present type = 'function'; % then access like any function else type = 'unknown'; end %% Let's see if its a class by checking if methods returns % What about classdef in oct file above? Should we do this even if % type is 'octfile'? if (strcmp (type, 'unknown')) if (~ isempty (w) && strcmp (w(1), '@')) temp = w(2:end); else temp = w; end try temp = methods(temp); type = 'class'; catch type = 'unknown'; end end if (strcmp (type, 'unknown')) if (exist(w, 'dir')) type = 'dir'; elseif (exist(w, 'file') || exist(w, 'builtin') || exist(w) == 103) type = 'function'; else type = 'unknown'; end end % This covers anything that we can get help from that wasn't covered above, % notably "doctest class.method". Quite possibly some other things too. if (strcmp (type, 'unknown')) try if (~isempty (help (w))) type = 'function'; end catch % no-op end end else % Matlab if (strcmp(w(1), '@')) && ~isempty(methods(w(2:end))) % covers "doctest @class", but not "doctest @class/method" type = 'class'; elseif ~isempty(methods(w)) % covers "doctest class" type = 'class'; elseif (exist(w, 'dir')) type = 'dir'; elseif exist(w, 'file') || exist(w, 'builtin'); type = 'function'; elseif ~isempty(help(w)) % covers "doctest class.method" and "doctest class/method" % no try-catch needed as no error when w has no help type = 'function'; else type = 'unknown'; end % Note: ambiguous what happens for "doctest @class/method"... as it is % for "help @class/method", e.g., "help @class/class" does not give the % constructor's help. end % Deal with directories if (strcmp(type, 'dir')) if (strcmp(w, '.')) if (depth == 0) % cheap hack to not indent when calling "doctest ." depth = -1; end else spaces = repmat(' ', 1, 2*depth); if (strcmp(w(end), filesep())) slashchar = ''; else slashchar = filesep(); end if (verbose) fprintf(fid, '%s%s%s\n', spaces, w, slashchar); end end oldcwd = chdir(w); files = dir('.'); for i=1:numel(files) f = files(i).name; if (exist(f, 'dir')) if (strcmp(f, '.') || strcmp(f, '..')) % skip "." and ".." continue elseif (strcmp(f(1), '@')) % class, don't skip if nonrecursive elseif (~ recursive) % skip all directories continue elseif (strcmp(f(1), '.')) %fprintf(fid, 'Ignoring hidden directory "%s"\n', f) continue end else [~, ~, ext] = fileparts(f); if (~ any(strcmpi(ext, ... {'.m' '.texinfo' '.texi' '.txi' '.tex' '.oct' '.mex'}))) %fprintf(fid, 'Debug: ignoring file "%s"\n', f) continue end end summary = doctest_collect(f, directives, summary, recursive, verbose, depth + 1, fid); end chdir(oldcwd); return end % Build structure array with the following fields: % TARGETS(i).name Human-readable name of test. % TARGETS(i).link Hyperlink to test for use in Matlab. % TARGETS(i).docstring Associated docstring. % TARGETS(i).error: Contains error string if extraction failed. % TARGETS(i).depth How "deep" in a recursive traversal are we if strcmp(type, 'function') target = collect_targets_function(w); target.depth = depth; targets = [target]; elseif strcmp(type, 'class') targets = collect_targets_class(w, depth); elseif strcmp (type, 'octfile') targets = collect_targets_octfile (w, depth); elseif strcmp(type, 'texinfo') target = struct(); target.name = w; target.link = ''; target.depth = depth; [target.docstring, target.error] = parse_texinfo(fileread(w)); targets = [target]; else target = struct(); target.name = w; target.link = ''; target.depth = depth; target.docstring = ''; target.error = 'Function or class not found.'; targets = [target]; end % update summary summary.num_targets = summary.num_targets + numel(targets); % get terminal color codes [color_ok, color_err, color_warn, reset] = doctest_colors(fid); for i=1:numel(targets) % run doctests for target and update statistics target = targets(i); spaces = repmat(' ', 1, 2*target.depth); dots = repmat('.', 1, 55 - numel(target.name) - 2*target.depth); if (verbose) fprintf(fid, '%s%s %s ', spaces, target.name, dots); end % extraction error? if target.error summary.num_targets_with_extraction_errors = summary.num_targets_with_extraction_errors + 1; if (verbose) fprintf(fid, [color_err 'EXTRACTION ERROR' reset '\n\n']); fprintf(fid, ' %s\n\n', target.error); end continue; end % run doctest results = doctest_run_docstring(target.docstring, directives); % determine number of tests passed num_tests = numel(results); num_tests_passed = 0; for j=1:num_tests if results(j).passed num_tests_passed = num_tests_passed + 1; end end % update summary summary.num_tests = summary.num_tests + num_tests; summary.num_tests_passed = summary.num_tests_passed + num_tests_passed; if num_tests_passed == num_tests summary.num_targets_passed = summary.num_targets_passed + 1; end if num_tests == 0 summary.num_targets_without_tests = summary.num_targets_without_tests + 1; end if (verbose) % pretty print outcome if num_tests == 0 fprintf(fid, 'NO TESTS\n'); elseif num_tests_passed == num_tests fprintf(fid, [color_ok 'PASS %4d/%-4d' reset '\n'], num_tests_passed, num_tests); else fprintf(fid, [color_err 'FAIL %4d/%-4d' reset '\n\n'], num_tests - num_tests_passed, num_tests); for j = 1:num_tests if ~results(j).passed fprintf(fid, ' >> %s\n\n', results(j).source); fprintf(fid, [ ' expected: ' '%s' '\n' ], results(j).want); fprintf(fid, [ ' got : ' color_err '%s' reset '\n' ], results(j).got); if results(j).xfail fprintf(fid, ' expected failure, but test succeeded!'); end fprintf(fid, '\n'); end end end end end end function target = collect_targets_function(w) target = struct(); target.name = w; if is_octave() target.link = ''; else target.link = sprintf('%s', which(w), w); end [target.docstring, target.error] = extract_docstring(target.name); end function targets = collect_targets_class(w, depth) if (strcmp(w(1), '@')) % Octave methods('@foo') gives java error, Matlab just says "No methods" w = w(2:end); end % workaround github.com/catch22/octave-doctest/issues/135 by % accessing all non-constructor method help text *before* "help obj" if (is_octave () && compare_versions (OCTAVE_VERSION, '7.0.0', '<')) meths = methods (w); for i=1:numel (meths) if (~ strcmp (meths{i}, w)) % skip @obj/obj name = sprintf ('@%s%s%s', w, filesep (), meths{i}); [docstring, format] = get_help_text (name); end end end % end workaround % First, "help class". For classdef, this differs from "help class.class" % (general class help vs constructor help). For old-style classes we will % probably end up testing the constructor twice but... meh. target.name = w; if is_octave() target.link = ''; else target.link = sprintf('%s', which(w), w); end target.depth = depth; [target.docstring, target.error] = extract_docstring(target.name); targets = target; % Next, add targets for all class methods meths = methods(w); meths = unique (meths); % Issue #260 for i=1:numel(meths) target = struct(); if is_octave() if compare_versions (OCTAVE_VERSION, '7.0.0', '>=') && exist (w, "class") == 8 % classdef on newish Octave: use cls.method if strcmp (meths{i}, w) % TODO: gathering the ctor help fails https://savannah.gnu.org/bugs/?62803 continue end target.name = sprintf ('%s.%s', w, meths{i}); target.link = ''; else % use @cls/method for old-style classes https://savannah.gnu.org/bugs/?61521 target.name = sprintf ('@%s%s%s', w, filesep (), meths{i}); target.link = ''; end else target.name = sprintf('%s.%s', w, meths{i}); target.link = sprintf('%s', which(w), meths{i}, target.name); end target.depth = depth; [target.docstring, target.error] = extract_docstring(target.name); targets = [targets; target]; end end function targets = collect_targets_octfile (file, depth) % first target is the name of the octfile (w/o extension) [~, basename, ext] = fileparts (file); assert (strcmp (ext, '.oct')) target = collect_targets_function (basename); target.name = file; target.depth = depth; targets = [target]; % octfile may have many fcns in it: find them using the autoload map autoloadmap = autoload (); len = numel (file); % matches both "/foo/bar.oct" and "/baz/bar.oct"; uncommon in practice pmatch = @(e) (numel (e.file) >= len) && strcmp (e.file(end-len+1:end), file); idx = find (arrayfun (pmatch, autoloadmap)); if (~ isempty (idx)) % indicate that octfile has other fcns, and indent those targets targets(1).name = [targets(1).name ':']; for i = 1:numel (idx) f = autoloadmap(idx(i)).function; target = collect_targets_function (f); target.depth = depth + 1; targets = [targets; target]; end end end function [docstring, error] = extract_docstring(name) if is_octave() [docstring, format] = get_help_text(name); if strcmp(format, 'texinfo') [docstring, error] = parse_texinfo(docstring); elseif strcmp(format, 'plain text') error = ''; elseif strcmp(format, 'Not documented') assert (isempty (docstring)) error = ''; elseif strcmp(format, 'Not found') % looks like "doctest test_no_docs.m" gets us here: octave bug? if (regexp(name,'\.m$')) assert (isempty (docstring)) error = ''; else assert (isempty (docstring)) error = 'Not an m file.'; end else format warning('Doctest:unexpected-format', 'Unexpected format in that file/function'); error = ''; end else docstring = help(name); error = ''; end end function [docstring, error] = parse_texinfo(str) docstring = ''; error = ''; % no example blocks? not an error, but nothing to do if (isempty(strfind(str, '@example'))) % error = 'no @example blocks'; return end % Normalize line endings in files which have been edited in Windows % This simplifies the regular expressions below. str = strrep (str, sprintf ('\r\n'), sprintf ('\n')); % The subsequent regexprep would fail if the example block is located right % at the beginning of the file. This is probably a bug in regexprep and is % only possible inside included texinfo files. if (isempty (regexp (str, '^\s', 'once'))) str = cstrcat (sprintf ('\n'), str); end % Mark the occurrence of “@example” and “@end example” to be able to find % example blocks after conversion from texi to plain text. Also consider % indentation, so we can later correctly unindent the example's content. % These should work, but I keep hitting ARM-specific when $1 is empty: % https://savannah.gnu.org/bugs/index.php?52810 % TODO: fixed in 4.2.2, so can revert this once we drop 4.2.1 support %str = regexprep (str, ... % '^([ \t]*)(\@example)(.*)$', ... % [ '$1$2$3\n', ... % retain original line % '$1###### EXAMPLE START ######'], ... % 'lineanchors', 'dotexceptnewline', 'emptymatch'); %str = regexprep (str, ... % '^([ \t]*)(\@end example)(.*)$', ... % [ '$1###### EXAMPLE STOP ######\n', ... % '$1$2$3'], ... % retain original line % 'lineanchors', 'dotexceptnewline', 'emptymatch'); % Instead we do it manually [S, E, TE, M, T, NM, SP] = regexp (str, '^([ \t]*)(\@example)(.*)$', ... 'lineanchors', 'dotexceptnewline', 'emptymatch'); str = SP{1}; for i=1:length (T) str = [str ... T{i}{:} sprintf('\n') ... % retain original line T{i}{1} '###### EXAMPLE START ######' ... SP{i+1}]; end [S, E, TE, M, T, NM, SP] = regexp (str, '^([ \t]*)(\@end example)(.*)$', ... 'lineanchors', 'dotexceptnewline', 'emptymatch'); str = SP{1}; for i=1:length (T) str = [str ... T{i}{1} '###### EXAMPLE STOP ######' sprintf('\n') ... T{i}{:} ... % retain original line SP{i+1}]; end % special comments "@c doctest: cmd" are translated % FIXME the expression would also match @@c doctest: ... re = [ '(?:\@c(?:omment)?\s' ... % @c or @comment, ?: means no token '|#|%)\s*' ... % or one of #,% '(doctest:\s*.*)' ]; % want the doctest token str = regexprep (str, re, '% $1', 'dotexceptnewline'); % We use eval to not produce compile errors in Matlab, % the __makeinfo__ function exists in Octave only. [str, err] = eval('__makeinfo__ (str, ''plain text'')'); if (err ~= 0) error = sprintf('__makeinfo__ returned error code %d', err); return end % Normalize end of line characters again. __makeinfo__ returns end of line % characters depending on the current OS. Since we want Unix line endings, % the conversion is only required under Windows. if (ispc ()) str = strrep (str, sprintf ('\r\n'), sprintf ('\n')); end % extract examples and discard everything else T = regexp (str, ... [ '(^[ \t]*###### EXAMPLE START ######', ... '.*?', ... '###### EXAMPLE STOP ######$)'], ... 'tokens', 'lineanchors'); if (isempty (T)) error = 'malformed @example blocks'; return end % post-process each example block for i = 1 : length (T) % flatten assert (numel (T{i}), 1); T{i} = T{i}{1}; % unindent indent = regexp (T{i}, '#', 'once') - 1; T{i} = regexprep (T{i}, sprintf ('^[ \t]{%d}', indent), '', 'lineanchors'); % remove EXAMPLE markers T{i} = regexprep (T{i}, ... '[ \t]*###### EXAMPLE ST(?:ART|OP) ######(?:\n|$)', ... ''); if (regexp (T{i}, '^\s*$', 'once', 'emptymatch')) error = 'empty @example blocks'; return end if (regexp (T{i}, '^\s*>>', 'once')) % First nonblank line starts with '>>': assume diary style. However, % we strip @result and @print macros (TODO: perhaps unwisely?) L = strsplit (T{i}, '\n'); L = regexprep (L, '^(\s*)(?:⇒|=>|⊣|-\||error→|error->)', '$1', 'once', 'lineanchors'); T{i} = strjoin (L, '\n'); continue end % Hack: the @example block is commonly mis-used to store non-examples such as % diagrams or math. Delete an example block that has no indicated output. % (Hard to leave for "later" as we don't keep track of @example blocks.) R1 = regexp (T{i}, '^\s*(⇒|=>|⊣|-\||error→|error->)', 'lineanchors'); R2 = regexp (T{i}, '(doctest:\s+-TEXINFO_SKIP_BLOCKS_WO_OUTPUT)'); T{i} = regexprep (T{i}, '(doctest:\s+-TEXINFO_SKIP_BLOCKS_WO_OUTPUT)', ''); if (isempty (R1) && isempty (R2)) T{i} = ''; continue end % split into lines L = strsplit (T{i}, '\n'); % Categorize input and output lines in the example using % @result and @print macros. Everything else, including comment lines and % empty lines, is categorized as input (for now). Linput = cellfun ('isempty', regexp (L, '^\s*(⇒|=>|⊣|-\||error→|error->)', 'once')); if (not (Linput (1))) error = 'no command: @result on first line?'; return end % Output lines may be wrapped or output goes over several lines and not % every line is preceded by “=>”. indent = regexp(L, '\S', 'once'); indent(cellfun ('isempty', indent)) = inf; indent = [indent{:}] - 1; row = 1; while (row < numel (L)) begin_of_input = row; begin_of_output = row + find (not (Linput(row + 1 : end)), 1); if (isempty (begin_of_output)) begin_of_output = numel (L) + 1; end end_of_input = begin_of_output - 1; % determine minimum indentation of input lines min_indent = min (indent(begin_of_input : end_of_input)); % Find next input line with an equal or less indentation to determine the % end of the output. row = begin_of_output ... + find (Linput(begin_of_output + 1: end) ... & (indent(begin_of_output + 1: end) <= min_indent), ... 1); if (isempty (row)) row = numel (L) + 1; end end_of_output = row - 1; if (end_of_output <= numel (L)) Linput (begin_of_output : end_of_output) = false; end % Mark verified input lines as such L{begin_of_input} = ['>> ' L{begin_of_input}]; L(begin_of_input + 1 : end_of_input) = ... cellfun (@(s) ['.. ' s], L(begin_of_input + 1 : end_of_input), ... 'UniformOutput', false); end % strip @result and @print macro output Loutput = not (Linput); L(Loutput) = regexprep (L(Loutput), ... '^(\s*)(?:⇒|=>|⊣|-\||error→|error->)', ... '$1', ... 'once', 'lineanchors'); T{i} = strjoin (L, '\n'); end docstring = strjoin (T, '\n'); end doctest-0.8.0/inst/private/doctest_colors.m0000644000000000000000000000145614354676362015733 0ustar function [color_ok, color_err, color_warn, reset] = doctest_colors(fid) %DOCTEST_COLORS Return terminal color codes. % % FIXME: Shouldn't use colors if stdout is not a TTY. %% % Copyright (c) 2015 Michael Walter % Copyright (c) 2015, 2017 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause % by default, no colors color_ok = ''; color_err = ''; color_warn = ''; reset = ''; % only use colors in Octave, when printing to stdout, and when terminal supports colors if (is_octave()) have_colorterm = index(getenv('TERM'), 'color') > 0; if fid == stdout && have_colorterm % hide terminal escapes from Matlab color_ok = eval('"\033[1;32m"'); % green color_err = eval('"\033[1;31m"'); % red color_warn = eval('"\033[1;35m"'); % purple reset = eval('"\033[m"'); end end end doctest-0.8.0/inst/private/doctest_compare.m0000644000000000000000000000460014354676362016052 0ustar function match = doctest_compare(want, got, goterr, normalize_whitespace, ellipsis) %DOCTEST_COMPARE Check if two strings match. % % Returns true if string GOT matches the template string WANT. Basically % WANT and GOT should be identical, except: % % * whitespace at the start/end of each line is trimmed; % * multiple spaces are collapsed (if NORMALIZE_WHITESPACE is true); % * WANT can have "..."; matches anything in GOT (if ELLIPSIS is true); % * WANT can omit "ans = "; % * various other nonsense of unknown current relevance. %% % Copyright (c) 2010 Thomas Grenfell Smith % Copyright (c) 2015 Michael Walter % Copyright (c) 2015-2016 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause % This looks bad, like hardcoding for lower-case "a href" % and a double quote... but that's what MATLAB looks for too. got = regexprep(got, ' octave-doctest www.octave.org-octave.desktop Doctest Find and run example code within documentation

Formatted blocks of example code are extracted from documentation files and executed to confirm their output is correct. This can be part of a testing framework or simply to ensure that documentation stays up-to-date during software development.

development software testing testing documentation https://octave.sourceforge.io/doctest https://github.com/catch22/octave-doctest/issues/new FSFAP BSD-3-Clause Octave-Forge Community octave-maintainers@gnu.org
doctest-0.8.0/test/0000755000000000000000000000000014354676362011051 5ustar doctest-0.8.0/test/.hidden/0000755000000000000000000000000014354676362012362 5ustar doctest-0.8.0/test/.hidden/test_dont_run.m0000644000000000000000000000013614354676362015427 0ustar function test_dont_run() % This is in a dot directory so it should not run % >> a = 5 % a = 6 doctest-0.8.0/test/.oct-config0000644000000000000000000000001714354676362013100 0ustar encoding=utf-8 doctest-0.8.0/test/@test_class/0000755000000000000000000000000014354676362013315 5ustar doctest-0.8.0/test/@test_class/test_class.m0000644000000000000000000000037214354676362015641 0ustar function obj = test_class % % >> disp(class(test_class)) % test_class % % % >> methods test_class % Methods for class test_class: % test_class test_method obj = struct; obj.name = 'Default Name'; obj.age = 42; obj = class(obj, 'test_class'); end doctest-0.8.0/test/@test_class/test_method.m0000644000000000000000000000027314354676362016014 0ustar function result = test_method(obj, varargin) % % >> m = test_class; disp(test_method(m)) % Default Name is 42 years old. result = sprintf('%s is %d years old.', obj.name, obj.age); end doctest-0.8.0/test/@test_classdef/0000755000000000000000000000000014354676362013774 5ustar doctest-0.8.0/test/@test_classdef/amethod.m0000644000000000000000000000013514354676362015572 0ustar function amethod(obj) % This method is stored in a separate file. % >> b = 2 + 2 % b = 4 end doctest-0.8.0/test/@test_classdef/test_classdef.m0000644000000000000000000000157614354676362017006 0ustar classdef test_classdef %TEST_CLASSDEF A test for classdef classes % % Some tests: % >> 6 + 7 % ans = 13 % % >> a = test_classdef() % a = % class name = "default", age = 42 % % % This general help text should be shown for "help test_classdef". % % There are also tests in the methods below. properties name age end methods function obj = test_classdef(n, a) % test_classdef: constructor help text % % not sure how to see this but here's an embedded doctest % % >> a = 13 + 1 % a = 14 if (nargin ~= 2) obj.name = 'default'; obj.age = 42; else obj.name = n; obj.age = a; end end end methods function disp(obj) % disp method help text % >> a = 30 + 2 % a = 32 fprintf('class name = "%s", age = %d\n', obj.name, obj.age) end end end doctest-0.8.0/test/@test_shadow/0000755000000000000000000000000014354676362013475 5ustar doctest-0.8.0/test/@test_shadow/test_shadow.m0000644000000000000000000000022314354676362016174 0ustar function obj = test_shadow() % >> 6 + 7 % ans = 13 obj = struct(); obj.name = 'Do not shadow me bro'; obj = class(obj, 'test_shadow'); end doctest-0.8.0/test/README.md0000644000000000000000000000027114354676362012330 0ustar Part of the Octave-Doctest test-suite. This directory is recursively tested by `doctest`. Some `%!`-style built-in self-tests may be run here as well, check the Makefile for details. doctest-0.8.0/test/bist.m0000644000000000000000000001641014354676362012172 0ustar function bist() % built-in self tests for Doctest % % Doctest mostly tests itself but in some cases we want to ensure % exactly what is being tested and yet we cannot call doctest recursively % https://github.com/catch22/octave-doctest/issues/184 % % Copyright (c) 2019, 2022 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause end %!error doctest () %!error [a, b, c, d] = doctest ('double') %!assert (doctest ('doctest', '-quiet')) %!assert (~ doctest ('there_is_no_such_file', '-quiet')) %!assert (~ doctest ('@there_is_no_such_class', '-quiet')) %!assert (~ doctest ({'doctest', 'there_is_no_such_file'}, '-quiet')) %!test %! [n, t] = doctest ('doctest', '-quiet'); %! assert (n == t) %! assert (t >= 10) %!test %! [n, t, summ] = doctest ('doctest'); %! assert (n == t) %! assert (t >= 10) %! assert (summ.num_targets == 1) %! assert (summ.num_tests == t) %! assert (summ.num_tests_passed == n) %!test %! % list input %! [n, t1, summ] = doctest ({'doctest'}); %! [n, t2, summ] = doctest ({'doctest' 'doctest'}); %! assert (t2 == 2*t1) %! assert (summ.num_targets == 2) %!test %! % nonrecursion stays out of subdirs %! [n1, t1] = doctest ('test_dir', '-quiet'); %! [n2, t2] = doctest ('test_dir', '-nonrecursive', '-quiet'); %! assert (t2 < t1) %!test %! % maybe not recommended notation for classdef, but works for now... %! [nump, numt, summ] = doctest ('@test_classdef/amethod'); %! assert (nump == 1 && numt == 1) %!xtest %! % maybe not recommended notation for classdef %! [nump, numt, summ] = doctest ('@test_classdef/disp'); %! assert (nump == 1 && numt == 1) %!test %! % https://github.com/catch22/octave-doctest/issues/92 %! % Should have 4 targets and 5 tests %! % * general class help (2 tests) %! % * ctor (1 test) %! % * disp method (1 test) %! % * amethod in external file (1 test) %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [nump, numt, summ] = doctest ('test_classdef'); %! assert (nump == numt && numt >= 4) %! assert (summ.num_targets >= 3) %! end %!xtest %! % https://github.com/catch22/octave-doctest/issues/268 %! if (compare_versions (OCTAVE_VERSION(), '7.0.0', '>=')) %! [nump, numt, summ] = doctest ('classdef_infile'); %! assert (nump == numt && numt == 5) %! assert (summ.num_targets == 4) %! end %!test %! %% Issue #220, Issue #261, clear and w/o special order or workarounds %! if (compare_versions (OCTAVE_VERSION(), '7.0.0', '>=')) %! clear classes %! % doctest ('test_classdef') %! [numpass, numtest, summary] = doctest ('test_classdef'); %! assert (numpass == numtest) %! assert (summary.num_targets_without_tests == 0) %! end %!test %! %% Issue #220, workarounds for testing classdef are sensitive to %! % the order of tests above. Here we clear first. But we "preload" %! % some methods as a workaround. %! if (compare_versions (OCTAVE_VERSION(), '4.4.0', '>=')) %! clear classes %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! doc = help ('@test_classdef/amethod'); %! assert (length (doc) > 10) %! % dot notation broken before Octave 6 %! doc = help ('test_classdef.disp'); %! assert (length (doc) > 10) %! end %! % doctest ('test_classdef') %! [numpass, numtest, summary] = doctest ('test_classdef'); %! assert (numpass == numtest) %! if (compare_versions (OCTAVE_VERSION(), '4.4.0', '>=')) %! assert (summary.num_targets_without_tests <= 2) %! end %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! assert (summary.num_targets_without_tests <= 1) %! end %! % glorious future! Issue #261 %! % if (compare_versions (OCTAVE_VERSION(), 'X.Y.Z', '>=')) %! % assert (summary.num_targets_without_tests == 0) %! % end %! end %!test %! % maybe not recommended notation for classdef, but currently at least no error %! % https://github.com/catch22/octave-doctest/issues/199 %! [nump, numt, summ] = doctest ('@classdef_infile/disp'); %! assert (nump >= 0) %!xtest %! % maybe not recommended notation for classdef %! [nump, numt, summ] = doctest ('@classdef_infile/disp'); %! assert (nump == 1 && numt == 1) %!test %! % https://github.com/catch22/octave-doctest/issues/92 %! % Should have 3 targets and 4 tests %! % * general class help (2 tests) %! % * ctor (1 test) %! % * disp method (1 test) %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [nump, numt, summ] = doctest ('classdef_infile'); %! assert (nump == numt && numt >= 3) %! assert (summ.num_targets >= 2) %! end %!xtest %! % https://github.com/catch22/octave-doctest/issues/268 %! if (compare_versions (OCTAVE_VERSION(), '7.0.0', '>=')) %! [nump, numt, summ] = doctest ('classdef_infile'); %! assert (summ.num_targets == 3) %! assert (nump == numt && numt == 4) %! end %!test %! % monkey-patching methods to existing builtin-objects %! [nump, numt, summ1] = doctest ('logical'); %! % First, there is (at least) the "logical" builtin %! % >= b/c of https://github.com/catch22/octave-doctest/issues/87 %! assert (summ1.num_targets >= 1) %! savepath = addpath ('test_methods_in_subdir'); %! % there should be at least "logical" builtin and "logical.mynewmethod" %! [nump, numt, summ] = doctest ('logical'); %! assert (summ.num_targets >= 2) %! assert (summ.num_targets >= summ1.num_targets) %! assert (nump >= 3 && numt >= 3) %! path(savepath); %!function y = foo (x) %! % >> foo (2) %! % 4 %! % >> foo (10) %! % 20 %! y = 2*x; %!endfunction %!assert (doctest ('foo', '-quiet')) %!test %! [n, t, summ] = doctest ('foo'); %! assert (n == 2) %! assert (t == n) %! assert (summ.num_targets == 1) %!function y = bar (x) %! % >> bar (2) %! % 42 %! % >> bar (3) %! % 3 %! y = x; %!endfunction %!test %! [n, t, summ] = doctest ('bar'); %! assert (n == 1) %! assert (t == 2) %!test %! [n, t, summ] = doctest({}); %! assert (n == 0) %! assert (t == 0) %! assert (summ.num_targets == 0) %!test %! % skip empty targets %! [n, t, summ] = doctest({'', ''}); %! assert (n == 0) %! assert (t == 0) %! assert (summ.num_targets == 0) %! assert (summ.num_targets_with_extraction_errors == 0) %!test %! % skip empty targets %! [n1, t1, summ1] = doctest('doctest'); %! [n2, t2, summ2] = doctest({'', '', 'doctest', ''}); %! assert (n1 == n2) %! assert (t1 == t2) %! assert (summ1.num_targets == summ2.num_targets) %! assert (summ2.num_targets_with_extraction_errors == 0) %!test %! % correct number of tests %! [n, t, summ] = doctest('test_tab_before_prompt'); %! assert (n == 2) %!test %! % correct number of error tests %! [n, t, summ] = doctest('test_error'); %! assert (t == 4) %!test %! % class inside a package %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [n, t, summary] = doctest ("containers.Map"); %! assert (n == t) %! assert (summary.num_targets >= 10) % lots of methods %! end %!test %! % classdef.method %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [n, t, summary] = doctest ("test_classdef.disp"); %! assert (n == t) %! assert (n == 1) %! end %!test %! % classdef.method, where method is external file %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [n, t, summary] = doctest ("test_classdef.amethod"); %! assert (n == t) %! assert (n == 1) %! end %!test %! % classdef.method %! if (compare_versions (OCTAVE_VERSION(), '6.0.0', '>=')) %! [n, t, summary] = doctest ("classdef_infile.disp"); %! assert (n == t) %! assert (n == 1) %! end doctest-0.8.0/test/bist_skip_xfail_errors.m.txt0000644000000000000000000000117614354676362016620 0ustar function bist_skip_xfail_errors() % >> a = 42 % a = 42 % % % The directive has an undefined error % >> a = 43 %doctest: +SKIP_IF(truthy) % a = 43 % % % The directive failed; test should not have run % >> a % a = 42 % % % The directive has an undefined error % >> b = 44 %doctest: +XFAIL_IF(undef) % b = 44 % % % The directive has a syntax error % >> b = 45 %doctest: +XFAIL_IF(\m/) % b = 45 % % % An actual passing test % >> c = 46 % c = 46 % % % An actual failing test % >> c = 47 % c = 4200 end %!test %! % some are supposed to fail %! [n, t, summ] = doctest('bist_skip_xfail_errors'); %! assert (n == 3) %! assert (t == 7) doctest-0.8.0/test/classdef_infile.m0000644000000000000000000000141214354676362014337 0ustar classdef classdef_infile %CLASSDEF_INFILE A classdef living in a single m-file % % Some tests: % >> 6 + 7 % ans = 13 % % >> a = classdef_infile() % a = % class name = "default", age = 42 % % % This general help text should be shown for "help classdef_infile". % % There are also tests in the methods below. properties name age end methods function obj = classdef_infile(n, a) % constructor % >> a = 13 + 1 % a = 14 if (nargin ~= 2) obj.name = 'default'; obj.age = 42; else obj.name = n; obj.age = a; end end end methods function disp(obj) % >> a = 30 + 2 % a = 32 fprintf('class name = "%s", age = %d\n', obj.name, obj.age) end end end doctest-0.8.0/test/examples/0000755000000000000000000000000014354676362012667 5ustar doctest-0.8.0/test/examples/.oct-config0000644000000000000000000000001714354676362014716 0ustar encoding=utf-8 doctest-0.8.0/test/examples/greet.m0000644000000000000000000000016214354676362014152 0ustar function greet(user) % Returns a greeting. % % >> greet World % % Hello, World! disp(['Hello, ' user '!']); end doctest-0.8.0/test/private/0000755000000000000000000000000014354676362012523 5ustar doctest-0.8.0/test/private/test_in_private_dir.m0000644000000000000000000000006214354676362016734 0ustar function test_in_private_dir() % >> a = 5 % a = 5 doctest-0.8.0/test/test_angle_brackets.m0000644000000000000000000000165414354676362015240 0ustar function s = test_angle_brackets() % https://savannah.gnu.org/bugs/?45084 (Fixed in Octave 4.0) % % Copyright (c) 2015-2016, 2022 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause % % Fails on Octave 3.8 % >> oct38 = DOCTEST_OCTAVE && compare_versions(OCTAVE_VERSION, '4.0.0', '<'); % % % >> disp (test_angle_brackets ()) % doctest: +XFAIL_IF(oct38) % I <3 U % % % Slightly off-topic but newer Matlab have quotes around strings. % % Here's the Octave version, without quotes: % >> s = test_angle_brackets() % doctest: +SKIP_IF(oct38 || DOCTEST_MATLAB) % s = I <3 U % >> s = '

I heart you

' % doctest: +SKIP_IF(oct38 || DOCTEST_MATLAB) % s =

I heart you

% % % On Matlab, we need string indicators in the display: % >> s = test_angle_brackets() % doctest: +SKIP_IF(DOCTEST_OCTAVE) % s = 'I <3 U' % >> s = '

I heart you

' % doctest: +SKIP_IF(DOCTEST_OCTAVE) % s = '

I heart you

' s = 'I <3 U'; doctest-0.8.0/test/test_ans.m0000644000000000000000000000041314354676362013045 0ustar % Copyright (c) 2015 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause % % >> 4 % ans = 4 % % % >> ans % ans = 4 % % % >> 5 % doctest: +SKIP % ans = 5 % % % >> ans % ans = 4 % % % >> 6 % doctest: +XFAIL % ans = 7 % % % >> ans % ans = 6 doctest-0.8.0/test/test_ans.texinfo0000644000000000000000000000056614354676362014276 0ustar @c Copyright (c) 2015 Oliver Heimlich @c SPDX-License-Identifier: BSD-3-Clause @example >> 4 ans = 4 @end example @example >> ans ans = 4 @end example @example >> 5 @c doctest: +SKIP ans = 5 @end example @example >> ans ans = 4 @end example @example >> 6 @c doctest: +XFAIL ans = 7 @end example @example >> ans ans = 6 @end example doctest-0.8.0/test/test_blank_match.m0000644000000000000000000000027414354676362014534 0ustar function s = test_blank_match() % Issue #46 % % >> a = 3 + 4; % ... % % % Copyright (c) 2015 Michael Walter % Copyright (c) 2015 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause doctest-0.8.0/test/test_clear.m0000644000000000000000000000051514354676362013355 0ustar function test_clear() % Easy things first, clearing one variable % >> a = 6; % >> b = 7; % >> clear a % >> b % b = 7 % >> a % ...ndefined ... % % % Harder: % >> clear % >> a % ...ndefined ... % % % >> a = 4 % a = 4 % % % "clear all" clears stuff inside persistent vars % >> clear all % >> a % ...ndefined ... % % % >> a = 5 % a = 5 doctest-0.8.0/test/test_clear_all_first.m0000644000000000000000000000034314354676362015413 0ustar function test_clear_all_first() % If we "clear all" very early, our implementation may break if % subfunctions haven't yet been called. At least on Octave 4.2.1. % >> clear all % >> a % ...ndefined ... % % % >> a = 6 % a = 6 doctest-0.8.0/test/test_clear_isoctave.m0000644000000000000000000000047614354676362015260 0ustar function test_clear_isoctave() % Easy things first, clearing one variable % >> a = 6 % a = 6 % % % >> clear % >> a % ...ndefined ... % % % >> clear all % >> a % ...ndefined ... % % % Make sure these macros are still available after a clear % >> a = 42 % doctest: +XFAIL_IF(DOCTEST_OCTAVE | DOCTEST_MATLAB) % a = 0 doctest-0.8.0/test/test_comments.texinfo0000644000000000000000000000047014354676362015334 0ustar @example @group A = 5 @result{} A = 5 @comment Don't break my test @end group @end example @example @group A = 6 @comment My achy breaky test @result{} A = 6 @end group @end example @example @group A = 7 @*@c I just don't think my @result{} A = 7 @c test would understand @end group @end example doctest-0.8.0/test/test_comments_with_directives.m0000644000000000000000000000044714354676362017374 0ustar function test_comments_with_directives() % >> a = 6 %doctest: +XFAIL % comment (with parenthetical) % b = 5 % % % >> a = 7 % doctest: +XFAIL_IF (true) % comment % b = 5 % % % >> a = 8 % doctest: +XFAIL_IF (false) % comment (with parenthetical) % a = 8 doctest-0.8.0/test/test_compare_backspace.m0000644000000000000000000000114614354676362015712 0ustar function test_compare_backspace() % Matlab appears to emit backspace characters (0x08) for no apparent reason. % This doctest verifies that backspace characters are correctly processed % before comparison. Note a bit of fuss here because Octave needs this escape % sequence in double quotes which Matlab won't parse. % % >> if (exist('OCTAVE_VERSION')) % .. eval('sprintf("Hi, no question mark here?\x08 goodbye")') % .. else % .. disp(sprintf('Hi, no question mark here?\x08 goodbye')) % .. end % % Hi, no question mark here goodbye % % % All of the doctests should pass, and they manipulate this function. % doctest-0.8.0/test/test_compare_hyperlinks.m0000644000000000000000000000043514354676362016166 0ustar function test_compare_hyperlinks() % There are some tricky things that Matlab does to strings, such as adding % hyperlinks to help. We remove those before comparison, as verified by the % following doctest: % % >> disp('Hi there!
foo') % Hi there! foo doctest-0.8.0/test/test_deprecated.m0000644000000000000000000000030214354676362014361 0ustar function test_deprecated() % % Copyright (c) 2019 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause % % "??? " for errors deprecated 2019-10 % >> nosuchfcn(42) % ??? ...ndefined... % % doctest-0.8.0/test/test_diary_style.texinfo0000644000000000000000000000056714354676362016046 0ustar One is allowed to put diary-style tests within texinfo: @example @group >> a = 6 a = 6 @end group @end example @example @group >> % comments should >> # not interfere >> a = 7 a = 7 @end group @end example @example @group @c even these comments >> a = 7 a = 7 @end group @end example Blank lines ok: @example @group >> a = 7 a = 7 @end group @end example doctest-0.8.0/test/test_diary_style_mixed.texinfo0000644000000000000000000000031214354676362017220 0ustar Mixed, with print and result macros (do we want to allow this?) @example @group >> x = 8 @result{} x = 8 >> disp('abc'), s = disp('xyz') @print{} abc @result{} s = xyz @end group @end example doctest-0.8.0/test/test_dir/0000755000000000000000000000000014354676362012666 5ustar doctest-0.8.0/test/test_dir/.oct-config0000644000000000000000000000001714354676362014715 0ustar encoding=utf-8 doctest-0.8.0/test/test_dir/test1.m0000644000000000000000000000005214354676362014101 0ustar function test1() % >> a = 42 % a = 42 end doctest-0.8.0/test/test_dir/test_subdir/0000755000000000000000000000000014354676362015215 5ustar doctest-0.8.0/test/test_dir/test_subdir/.oct-config0000644000000000000000000000001714354676362017244 0ustar encoding=utf-8 doctest-0.8.0/test/test_dir/test_subdir/test2.m0000644000000000000000000000005214354676362016431 0ustar function test2() % >> b = 43 % b = 43 end doctest-0.8.0/test/test_ellipsis.m0000644000000000000000000000032614354676362014113 0ustar function test_ellipsis() % >> disp('...') % doctest: -ELLIPSIS % % ... % % % >> 1 + 2 % % ... % % % >> 1 + 2 % doctest: -ELLIPSIS % doctest: +XFAIL % % ... % % % >> 1 + 2 % doctest: -ELLIPSIS % % ans = 3 % doctest-0.8.0/test/test_ellipsis_match_empty.m0000644000000000000000000000043014354676362016501 0ustar function test_ellipsis_match_empty() % Ellipses should match empty string: % >> disp('abcdef') % abc...def % % % empty at ends: % >> disp('def') % ...def % % >> disp('def') % def... % % % Empty and whitespace: % >> disp('abc def') % abc ...def % % >> disp('abc def') % abc... def doctest-0.8.0/test/test_ellipsis_match_whitespace.m0000644000000000000000000000143114354676362017501 0ustar function test_ellipsis_match_whitespace() % Whitespace in middle % >> disp('abc def') % abc ... def % >> disp('abc def') % abc ... def % >> disp('abc def') % abc...def % % % Should fail: expects something surrounded by whitespace % >> disp('abc def') % doctest: +XFAIL % abc ... def % % % This is ok, because there are two whitespaces in input % >> disp('abc def') % abc ... def % % % Currently, ellipses will match empty the string but we trim begin/end of % lines, so these probably fail because there is nothing to match the space % after/before the "...". Probably ok to change this behaviour. % >> disp(' def') % doctest: +XFAIL % ... def % % >> disp('def ') % doctest: +XFAIL % def ... % % % However, these are ok: % >> disp('def') % ...def % % >> disp('def') % def... doctest-0.8.0/test/test_error.m0000644000000000000000000000116514354676362013422 0ustar function test_error() % >> a = 42 % a = 42 % % % >> 2 + (1 + !)) % doctest: +XFAIL_IF(DOCTEST_MATLAB) % parse error: % % syntax error % >>> 2 + (1 + !)) % doctest: +XFAIL_IF(DOCTEST_MATLAB) % ^ % % % Annoyingly, the doctest directive is still there and % appears in the error mesage. Perhaps we should move these % tests to bist.m. % % >> 2 + (1 + !)) % doctest: +XFAIL_IF(DOCTEST_MATLAB) % parse error: % % syntax error % >>> 2 + (1 + !)) % doctest: +XFAIL_IF(DOCTEST_MATLAB) % ^ % >> a = 43 % a = 43 % % % Copyright (c) 2019, 2022 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause doctest-0.8.0/test/test_error.texinfo0000644000000000000000000000140114354676362014633 0ustar Copyright (c) 2019 Colin B. Macdonald SPDX-License-Identifier: BSD-3-Clause @example 2 + (1 + !)) @error{} parse error: @error{} @error{} syntax error @error{} >>> 2 + (1 + !)) @error{} ^ @end example @example nosuchfcn(42) @error{} error: 'nosuchfcn' undefined near line 1... @end example @example nosuchfcn(42) @print{} error: 'nosuchfcn' undefined near line 1... @end example @example nosuchfcn(42) @error{} 'nosuchfcn' undefined near line 1... @end example In symbolic I had a failure when a test contained more code after an error. It did not pass without careful treatment of the typography of the texinfo error macro. @example a = 3; b = nosuchfcn(a) @error{} ... undefined... c = exp(a) @result{} c = 20.086 @end example doctest-0.8.0/test/test_format.m0000644000000000000000000000053214354676362013556 0ustar % Default number formatting % >> a = 1.3 % a = 1.3000 % % % If tests change it... % >> format long % >> b = 10/6 % b = 1.66666666...7 % % % ... they should change it back to defaults % >> format() % >> a % a = 1.3000 % % % TODO: should test that we restore the users settings, but probably % Issue #184 prevents doing this within our doctests. doctest-0.8.0/test/test_long_rows.m0000644000000000000000000000031114354676362014272 0ustar function y = test_long_rows() % >> repmat(1, 1, 50) % doctest: +XFAIL_IF(DOCTEST_MATLAB) % % ans = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 doctest-0.8.0/test/test_long_rows.texinfo0000644000000000000000000000023614354676362015520 0ustar @example repmat(1, 1, 50) @result{} ans = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 @end example doctest-0.8.0/test/test_methods_in_subdir/0000755000000000000000000000000014354676362015611 5ustar doctest-0.8.0/test/test_methods_in_subdir/.oct-config0000644000000000000000000000001714354676362017640 0ustar encoding=utf-8 doctest-0.8.0/test/test_methods_in_subdir/@logical/0000755000000000000000000000000014354676362017323 5ustar doctest-0.8.0/test/test_methods_in_subdir/@logical/mynewmethod.m0000644000000000000000000000030614354676362022040 0ustar function y = mynewmethod(x) %MYNEWMETHOD: monkey patch something onto class logical % >> a = mynewmethod(true); % >> double(a) % ans = 0 % >> double(islogical(a)) % ans = 1 y = ~ x; end doctest-0.8.0/test/test_multi_directives.m0000644000000000000000000000112614354676362015641 0ustar function test_multi_directives() % Dummy: % >> z = 0; % % % Will fail if we do not skip % >> s = 'a b' % doctest: +SKIP_IF (1 > 0) % doctest: -NORMALIZE_WHITESPACE % .. z = 1; % s = a b % % % and we did skip % >> z % z = 0 % % % % Will fail if we do not skip % >> s = 'a b' % my comment % doctest: -NORMALIZE_WHITESPACE % doctest: +SKIP_IF (true) % other comment % .. z = 2; % s = a b % % % and we did skip: % >> z % z = 0 % % % % >> s = 'a ...23 b' % doctest: -ELLIPSIS % doctest: +NORMALIZE_WHITESPACE % doctest: +XFAIL % .. z = 3; % s = a ... b % % % >> z % z = 3 doctest-0.8.0/test/test_multi_result.texinfo0000644000000000000000000000170714354676362016243 0ustar Current approach works for this block because the last line before a @@result becomes a command: @example @group [a, b] = deal (1, 2) @result{} a = 1 b = 2 c = 3 @result{} c = 3 d = 4, e = 5 @result{} d = 4 e = 5 @end group @end example But here we have trouble: @example @group [a, b] = deal (1, 2) @result{} a = 1 b = 2 c = 3 % I should be a command d = 4 @result{} c = 3 d = 4 @end group @end example A reasonable solution would be to use the intending level to help detect/classify lines as input/output. Here are some challenges for that: @example @group [a, b] = deal (1, 2) @result{} a = 1 b = 2 c = 3 d = 4 @result{} c = 3 d = 4 @end group @end example @example @group [a, b] = deal (1, 2) @result{} a = 1 b = 2 @comment don't mess up because of this outdented comment c = 3 d = 4 @result{} c = 3 d = 4 @end group @end example doctest-0.8.0/test/test_multi_return.texinfo0000644000000000000000000000136214354676362016241 0ustar Here we have no return value but only output: @example disp ('abc') @print{} abc @end example Here it is an return value: @example x = disp ('abc') @result{} x = abc @end example Here we have a combination of both: @example disp ('abc'); x = disp ('def') @print{} abc @result{} x = def @end example Here the warning is not part of the result: @example inv ([1 2; 2 4]) @print{} warning: ...matrix singular to machine precision... @result{} ans = Inf Inf Inf Inf @end example Here we have two results: @example [m, n] = size (zeros (1, 2)) @result{} m = 1 @result{} n = 2 @end example Intermediate results and printing: @example [m, n] = size (zeros (1, 2)), disp ('abc') @result{} m = 1 @result{} n = 2 @print{} abc @end example doctest-0.8.0/test/test_no_docs.m0000644000000000000000000000014214354676362013707 0ustar function test_no_docs() s = 'note this function has no docs: this should not cause an error'; doctest-0.8.0/test/test_not_an_mfile.txt0000644000000000000000000000033314354676362015302 0ustar % hello, I am not an m-file so I should not be doctested % % >> a = 6 % a = 7 % % % This test would fail if doctest finds it when traversing % a directory. If you run doctest on it directly, you should % get an error. doctest-0.8.0/test/test_shadow/0000755000000000000000000000000014354676362013375 5ustar doctest-0.8.0/test/test_shadow.m0000644000000000000000000000064014354676362013553 0ustar % Note this file shadows the class @test_shadow. The class will % take precedence: i.e., `doctest test_shadow` will test the class. % You can always override with `doctest test_shadow.m`. % % >> 2 + 2 % ans = 4 % >> 3 + 3 % ans = 6 % % % Note: in Matlab, help('test_shadow.m') returns the help for % '@test_shadow' even when the .m if explicitly given. So this % test will never run on Matlab. not_the_class = 42 doctest-0.8.0/test/test_shadow/.oct-config0000644000000000000000000000001714354676362015424 0ustar encoding=utf-8 doctest-0.8.0/test/test_shadow/test_in_shadow_dir.m0000644000000000000000000000043614354676362017426 0ustar function test_in_shadow_dir(x) % this test is in a directory shadowed/shadowing both a class % and an m-file. Its probably not entirely well-posed what % should happen here but on Octave at least, you can doctest % all three. % % >> a = 4 % a = 4 % >> a = 5 % a = 5 % >> a = 6 % a = 6 doctest-0.8.0/test/test_skip.m0000644000000000000000000000070714354676362013240 0ustar function test_skip() % This file should have 3 passed tests % % A test that would fail: % >> a = 5 % doctest: +SKIP % b = 7 % % % And a passing one: % >> a = 6 % a = 6 % % % Multiline input: % >> A = [1 2; % .. 3 4] % doctest: +SKIP % A = 42 % % % Put it on any line of multiline input: % >> A = [1 2; % doctest: +SKIP % .. 3 4] % A = 42 % % % Skip means not evaluated % >> a = 6 % a = 6 % >> a = 5 % doctest: +SKIP % >> a % a = 6 doctest-0.8.0/test/test_skip_comments.texinfo0000644000000000000000000000056514354676362016367 0ustar First actually set A (we'll check later that nobody messed it up) @example A = 5 @result{} A = 5 @end example @example A = 10 # doctest: +SKIP @result{} @end example @example A = 10 @c doctest: +SKIP @result{} A = 10 @comment doctest: +SKIP @result{} @end example Ensure A is still 5 (none of the skipped tests ran) @example A @result{} A = 5 @end example doctest-0.8.0/test/test_skip_if.m0000644000000000000000000000110614354676362013710 0ustar function test_skip_if() % This test should have 4 passing tests. % % Set up flags that determine test skipping. % >> my_true_flag = 1; % >> my_false_flag = 0; % % % A test that would fail: % >> a = 5 % doctest: +SKIP_IF(my_true_flag) % b = 7 % % % And a passing one: % >> a = 6 % doctest: +SKIP_IF(my_false_flag) % a = 6 % % % Check that it was indeed not skipped: % >> a % a = 6 % % % Multiline examples (put it on any line) % >> A = [1 2; % .. 3 4] % doctest: +SKIP_IF(my_true_flag) % A = 42 % % >> A = [1 2; % doctest: +SKIP_IF(my_true_flag) % .. 3 4] % A = 42 doctest-0.8.0/test/test_skip_if_multiple.m0000644000000000000000000000067014354676362015630 0ustar function test_skip_if_multiple() % Set up flags that determine test skipping. % >> false_flag = 0; % >> true_flag = 1; % >> z = 3; % % % The following test should not be skipped % >> z = 5 % doctest: +SKIP_IF(false_flag) % z = 5 % % % The following test should be skipped (thanks to the second condition) % >> z = 7 % doctest: +SKIP_IF(false_flag) % doctest: +SKIP_IF(true_flag) % w = 9 % % Check that it was indeed skipped: % >> z % z = 5 doctest-0.8.0/test/test_skip_malformed.texinfo0000644000000000000000000000033714354676362016505 0ustar @example @comment doctest: +SKIP Some verbatim text masquerading as an example (probably should live inside an @@verbatim block, but isn't). Should not raise an extraction error, because it is marked to skip. @end example doctest-0.8.0/test/test_skip_only_one.m0000644000000000000000000000015014354676362015132 0ustar function test_skip_only_one() % A file with just one skipped test: % >> a = 5 % doctest: +SKIP % b = 7 doctest-0.8.0/test/test_skip_unless.m0000644000000000000000000000113414354676362014624 0ustar function test_skip_unless() % This test should have 4 passing tests. % % Set up flags that determine test skipping. % >> my_true_flag = 1; % >> my_false_flag = 0; % % % A test that would fail: % >> a = 5 % doctest: +SKIP_UNLESS(my_false_flag) % b = 7 % % % And a passing one: % >> a = 6 % doctest: +SKIP_UNLESS(my_true_flag) % a = 6 % % % Check that it was indeed not skipped: % >> a % a = 6 % % % Multiline examples (put it on any line) % >> A = [1 2; % .. 3 4] % doctest: +SKIP_UNLESS(my_false_flag) % A = 42 % % >> A = [1 2; % doctest: +SKIP_UNLESS(my_false_flag) % .. 3 4] % A = 42 doctest-0.8.0/test/test_skip_wo_output.texinfo0000644000000000000000000000272414354676362016606 0ustar In the Octave community, the @code{@@example} block is commonly used non-semantically. While we do not endorse this, we do like dem ascii arts: @example _ _ _ __ _ _ __| | ___ ___| |_ ___ ___| |_ / _| |___ _| | / _` |/ _ \ / __| __/ _ \/ __| __| | |_| __\ \ /\ / / | | (_| | (_) | (__| || __/\__ \ |_ | _| |_ \ V V /|_| \__,_|\___/ \___|\__\___||___/\__| |_| \__| \_/\_/ (_) @end example (for later use) @example a = 4 @result{} a = 4 @end example Unfortunately, as there is no @strong{specified} output, this block is skipped too: @example a = 5; assert(false) @end example It really was skipped: @example a @result{} a = 4 @end example ``But wait'' you say, ``I want to test a block with no output!'' First, please patch Octave to use something like @code{@@verbatim} for diagrams, etc. Then patch doctest to remove this ``feature''. Done all that? No? Fine, well because we like you, there is a secret directive for you. It could disappear without notice in any future versions (we don't like you @strong{that} much). Try these: @example @comment doctest: -TEXINFO_SKIP_BLOCKS_WO_OUTPUT a = 5; @end example @example @comment doctest: +XFAIL @comment doctest: -TEXINFO_SKIP_BLOCKS_WO_OUTPUT b = 6; disp('do not skip me bro') @end example (note this test fails because it @strong{does} produce output). And indeed they were not skipped: @example a @result{} a = 5 b @result{} b = 6 @end example doctest-0.8.0/test/test_skip_wo_output_diary.m0000644000000000000000000000052014354676362016546 0ustar function test_skip_wo_output_diary() % % No output is specified here, so this code block would likely be % skipped if this was texinfo. But its not texinfo so this test % is expected to fail (and its a bug if it does not). % >> a = 5; % doctest: +XFAIL % .. disp('hi') % % % check that previous was not skipped % >> a % a = 5 doctest-0.8.0/test/test_skip_wo_output_diary.texinfo0000644000000000000000000000062114354676362017770 0ustar This file has diary-style within texinfo. Potential bugs here because of the empty block skipping feature. First, a block with no specified output: it should fail because it does have output: @example >> a = 5; >> disp('hi'); % doctest: +XFAIL @end example @example >> a a = 5 @end example The first command below should not invoke skipping: @example >> x = 5; >> y = x + 1 y = 6 @end example doctest-0.8.0/test/test_tab_before_prompt.m0000644000000000000000000000041114354676362015753 0ustar function test_tab_before_prompt() % This first test has spaces % >> a = 42 % a = 42 % % >> a = 43 % a = 43 % % % The second one has tabs: there should be two tests. % % Copyright (c) 2019, 2022 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause doctest-0.8.0/test/test_var.texinfo0000644000000000000000000000022614354676362014276 0ustar Make sure var macro can be used: @example @group @var{ABC} = 6 @result{} @var{ABC} = 6 @var{aBc} = 7 @result{} @var{aBc} = 7 @end group @end example doctest-0.8.0/test/test_warning.m0000644000000000000000000000020614354676362013731 0ustar function test_warning() % >> toeplitz ([1 2], [2 3]) % ...arning: ...olumn wins ...diagonal conflict... % ans = % 1 3 % 2 1 doctest-0.8.0/test/test_whitespace.m0000644000000000000000000000202514354676362014421 0ustar function test_whitespace() % >> disp('a b') % doctest: -NORMALIZE_WHITESPACE % a b % % >> disp('a b') % doctest: +NORMALIZE_WHITESPACE % a b % >> disp('a b') % doctest: +NORMALIZE_WHITESPACE % a b % % % Indenting is ok: % % >> disp('a b') % doctest: -NORMALIZE_WHITESPACE % % a b % % % But this should fail: % % >> disp('a b') % doctest: -NORMALIZE_WHITESPACE % doctest: +XFAIL % % a b % % % Multiline: Matlab and Octave format matrices differently but a % column vector is safe to use in cross-platform tests. % % >> A = [1; 2; -3] % doctest: -NORMALIZE_WHITESPACE % A = % 1 % 2 % -3 % % >> A % doctest: -NORMALIZE_WHITESPACE % % A = % % 1 % % 2 % % -3 % % % Matlab and Octave format differently, even for scalars, so % make sure our auto "ans = " bit still works. % % >> 42 % doctest: -NORMALIZE_WHITESPACE % 42 % % % Note: even very simple scalar tests like "x = 5" are difficult to % pass in both Octave and Matlab when using -NORMALIZE_WHITESPACE. doctest-0.8.0/test/test_windows_eol.texinfo0000644000000000000000000000031414354676362016035 0ustar @example @group A = 5 @result{} A = 5 @end group @end example @example @group A = 6 @result{} A = 6 @end group @end example @example @group >> A = 7 A = 7 @end group @end example doctest-0.8.0/test/test_xfail.m0000644000000000000000000000033214354676362013367 0ustar function test_xfail() % Let's initialize our dummy variable a. % >> a = 3 % a = 3 % % % The following test will fail: % >> a = 5 % doctest: +XFAIL % b = 7 % % % Check that it has been executed, though: % >> a % a = 5 doctest-0.8.0/test/test_xfail.texinfo0000644000000000000000000000014114354676362014605 0ustar This test is supposed to fail @example a = 5 @c doctest: +XFAIL @result{} b = 7 @end example doctest-0.8.0/test/test_xfail_if.m0000644000000000000000000000064514354676362014054 0ustar function test_xfail_if() % These flags control our expectations: % >> my_true_flag = 1; % >> my_false_flag = 0; % % % Let's initialize our dummy variable a: % >> a = 3 % a = 3 % % % The following test will fail: % >> a = 5 % doctest: +XFAIL_IF(my_true_flag) % b = 7 % % % Check that it has been executed, though: % >> a % a = 5 % % % This one should succeed, however: % >> a % doctest: +XFAIL_IF(my_false_flag) % a = 5 doctest-0.8.0/test/test_xfail_if_code.m0000644000000000000000000000070314354676362015041 0ustar function test_xfail_if_code() % % Initialize a dummy variable a: % >> a = 3 % a = 3 % % % The following test will fail: % >> a = 5 % doctest: +XFAIL_IF(6 + 0*now() >= 0) % b = 7 % % % Check that it has been executed: % >> a % a = 5 % % % This test succeeds and should not fail: % >> a % doctest: +XFAIL_IF(str2num('17') > 20) % a = 5 % % % There can be a space before the parenthesis % >> a % doctest: +XFAIL_IF (str2num('17') > 20) % a = 5 doctest-0.8.0/test/test_xfail_if_code.texinfo0000644000000000000000000000040614354676362016261 0ustar Dummy variable: @example a = 3 @result{} a = 3 @end example The following test will fail: @example @c doctest: +XFAIL_IF(6 + 0*now () >= 0) a = 5 @result{} b = 7 @end example value is changed (b/c xfail, not skip) @example a @result{} a = 5 @end example doctest-0.8.0/test/test_xfail_if_multiple.m0000644000000000000000000000073414354676362015766 0ustar function test_xfail_if_multiple() % Set up flags that determine test skipping. % >> false_flag = 0; % >> true_flag = 1; % >> z = 3; % % % The following test should succeed % >> z = 5 % doctest: +XFAIL_IF(false_flag) % z = 5 % % % Check that the first test was executed % >> z % z = 5 % % % The following test should be fail % >> z = 7 % doctest: +XFAIL_IF(false_flag) % doctest: +XFAIL_IF(true_flag) % w = 9 % % % Check that the second test was indeed executed % >> z % z = 7 doctest-0.8.0/test/test_xfail_unless.m0000644000000000000000000000066114354676362014765 0ustar function test_xfail_unless() % These flags control our expectations: % >> my_true_flag = 1; % >> my_false_flag = 0; % % % Let's initialize our dummy variable a: % >> a = 3 % a = 3 % % % The following test will fail: % >> a = 5 % doctest: +XFAIL_UNLESS(my_false_flag) % b = 7 % % % Check that it has been executed, though: % >> a % a = 5 % % % This one should succeed, however: % >> a % doctest: +XFAIL_UNLESS(my_true_flag) % a = 5 doctest-0.8.0/test/test_xskip_if_code.texinfo0000644000000000000000000000133114354676362016312 0ustar Dummy variable: @example a = 3 @result{} a = 3 @end example The regex for SKIP_IF argument should not cross newlines! First, note its ok to have syntax errors in skipped tests: @example @c doctest: +SKIP a = 5*(5+1)) @result{} b = 0 @end example But next we have a syntax error, combined with SKIP_IF code. The IF code should not glob the @code{a = } bit: might result in a syntax error if it did. @example @c doctest: +SKIP_IF(6 + 0*now () >= 0) a = 3*(4+1)) @result{} a = 15 @end example As above, but two SKIP_IF's @example @c doctest: +SKIP_IF(6 + 0*now () >= 0) @c doctest: +SKIP_IF(7 + 0*now () >= 0) a = 3*(4+1)) @result{} a = 15 @end example Finally, a is still 3 @example a @result{} a = 3 @end example doctest-0.8.0/test_extra/0000755000000000000000000000000014354676362012254 5ustar doctest-0.8.0/test_extra/README.md0000644000000000000000000000037314354676362013536 0ustar Part of the Octave-Doctest test-suite Contains tests that need dedicated syntax or version-specific tweaks to run. The built-in self tests in `run_tests.m` are run as part of our test suite. This directory will *not* be tested by `doctest` itself. doctest-0.8.0/test_extra/run_tests.m0000644000000000000000000001045114354676362014461 0ustar %% Copyright (c) 2022 Markus Mützel %% Copyright (c) 2022-2023 Colin B. Macdonald %% %% SPDX-License-Identifier: BSD-3-Clause %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions are met: %% %% 1. Redistributions of source code must retain the above copyright notice, %% this list of conditions and the following disclaimer. %% %% 2. Redistributions in binary form must reproduce the above copyright notice, %% this list of conditions and the following disclaimer in the documentation %% and/or other materials provided with the distribution. %% %% 3. Neither the name of the copyright holder nor the names of its %% contributors may be used to endorse or promote products derived from this %% software without specific prior written permission. %% %% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" %% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE %% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE %% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE %% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR %% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF %% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN %% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) %% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %% POSSIBILITY OF SUCH DAMAGE. function success = run_tests () success = true; is_oct = exist('OCTAVE_VERSION', 'builtin') ~= 0; if (~ is_oct) save_enc = feature ('DefaultCharacterSet'); meh = feature ('DefaultCharacterSet', 'CP1252'); chdir ('test_encoding') ok1 = doctest ('test_matlab_style_CP1252.m'); chdir ('..') meh = feature ('DefaultCharacterSet', 'UTF-8'); chdir ('test_encoding_utf8') ok2 = doctest ('test_matlab_style_utf8.m'); chdir ('..') meh = feature ('DefaultCharacterSet', save_enc); success = success && ok1 && ok2; end % Octave is tested by BIST, no action required here end %!test %! %% test with file that is not encoded in UTF-8 %! % this is a bare minimal test: the file is probably not read correctly %! % until Octave >= 7.0.0. %! path_orig = path (); %! warn_orig = warning ('off', 'octave:get_input:invalid_utf8'); %! unwind_protect %! addpath (canonicalize_file_name ('test_encoding')); %! assert (doctest ('test_CP1252.m', '-quiet')); %! unwind_protect_cleanup %! path (path_orig) %! warning (warn_orig) %! end %!test %! %% CP1252 to UTF-8 internally, check byte counts %! % A bug in Octave 7 requires that the folder containing the .oct-config file %! % is in the load path (not the current directory). %! if (compare_versions (OCTAVE_VERSION(), '7.0.0', '>=')) %! path_orig = path (); %! unwind_protect %! addpath (canonicalize_file_name ('test_encoding')); %! assert (doctest ('test_bytecount_CP1252.m', '-quiet')); %! assert (doctest ('test_matlab_style_CP1252.m', '-quiet')); %! unwind_protect_cleanup %! path (path_orig) %! end %! end %!test %! %% On Octave 8, we can go to the actual directory %! if (compare_versions (OCTAVE_VERSION(), '8.0.0', '>=')) %! d = pwd (); %! unwind_protect %! cd ('test_encoding'); %! assert (doctest ('test_bytecount_CP1252.m', '-quiet')); %! assert (doctest ('test_matlab_style_CP1252.m', '-quiet')); %! unwind_protect_cleanup %! cd (d) %! end %! end %!test %! % A bug in Octave 7 requires that the folder containing the .oct-config file %! % is in the load path (not the current directory). %! if (compare_versions (OCTAVE_VERSION(), '7.0.0', '>=')) %! path_orig = path (); %! unwind_protect %! addpath (canonicalize_file_name ('test_encoding_utf8')); %! assert (doctest ('test_matlab_style_utf8.m', '-quiet')); %! unwind_protect_cleanup %! path (path_orig) %! end %! end %!test %! %% On Octave 8, we can go to the actual directory %! if (compare_versions (OCTAVE_VERSION(), '8.0.0', '>=')) %! d = pwd (); %! unwind_protect %! cd ('test_encoding_utf8'); %! assert (doctest ('test_matlab_style_utf8.m', '-quiet')); %! unwind_protect_cleanup %! cd (d) %! end %! end doctest-0.8.0/test_extra/test_encoding/0000755000000000000000000000000014354676362015101 5ustar doctest-0.8.0/test_extra/test_encoding/.oct-config0000644000000000000000000000002614354676362017130 0ustar encoding=windows-1252 doctest-0.8.0/test_extra/test_encoding/test_CP1252.m0000644000000000000000000000352514354676362017137 0ustar %% Copyright (c) 2022 Markus Mtzel %% %% SPDX-License-Identifier: BSD-3-Clause %% %% Redistribution and use in source and binary forms, with or without %% modification, are permitted provided that the following conditions are met: %% %% 1. Redistributions of source code must retain the above copyright notice, %% this list of conditions and the following disclaimer. %% %% 2. Redistributions in binary form must reproduce the above copyright notice, %% this list of conditions and the following disclaimer in the documentation %% and/or other materials provided with the distribution. %% %% 3. Neither the name of the copyright holder nor the names of its %% contributors may be used to endorse or promote products derived from this %% software without specific prior written permission. %% %% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" %% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE %% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE %% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE %% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR %% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF %% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS %% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN %% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) %% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE %% POSSIBILITY OF SUCH DAMAGE. %% -*- texinfo -*- %% @deftypefn {} {} test_CP1252 () %% Test function with some non-ASCII characters from CP1252 %% %% %% %% @example %% s = ' ' %% @result{} s = %% @end example %% @end deftypefn function test_CP1252 () help ("test_CP1252"); endfunction doctest-0.8.0/test_extra/test_encoding/test_bytecount_CP1252.m0000644000000000000000000000155014354676362021227 0ustar %% Copyright (c) 2022 Colin B. Macdonald %% %% SPDX-License-Identifier: BSD-3-Clause %% -*- texinfo -*- %% @deftypefn {} {} test_bytecount_CP1252 () %% Test function with some non-ASCII characters from CP1252 %% %% This file is encoded in CP1252. Here is the euro symbol: %% @example %% s = '' %% @result{} s = %% @end example %% %% In CP1252, the euro symbol is encoded as a single byte. %% However, GNU Octave uses @code{utf-8} internally: when we %% load this docstring, it will have three bytes: %% @example %% double(s) %% @result{} %% 226 130 172 %% @end example %% %% Even better, we can look at the bits and compare to known %% values (e.g., see Wikipedia). %% @example %% uint8(s); %% dec2bin(ans) %% @result{} %% 11100010 10000010 10101100 %% @end example %% @end deftypefn function test_bytecount_CP1252 () % no-op endfunction doctest-0.8.0/test_extra/test_encoding/test_matlab_style_CP1252.m0000644000000000000000000000116214354676362021672 0ustar function s = test_matlab_style_CP1252() % Test function with some non-ASCII characters from CP1252 % % This file is encoded in CP1252. Here is the euro symbol: % >> s = ''; % >> disp(s) % % >> disp(test_matlab_style_CP1252()) % % % % In CP1252, the euro symbol is encoded as a single byte. % % Its not our business how this is storied internally (its utf-8 % on Octave, not sure on Matlab). But we can convert explicitly % to utf-8: % >> nums = unicode2native(s, 'utf-8'); % >> double(nums) % 226 130 172 % Copyright (c) 2022-2023 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause s = ''; end doctest-0.8.0/test_extra/test_encoding_utf8/0000755000000000000000000000000014354676362016047 5ustar doctest-0.8.0/test_extra/test_encoding_utf8/.oct-config0000644000000000000000000000001714354676362020076 0ustar encoding=utf-8 doctest-0.8.0/test_extra/test_encoding_utf8/test_matlab_style_utf8.m0000644000000000000000000000106514354676362022714 0ustar function s = test_matlab_style_utf8() % Test function with some non-ASCII characters in UTF-8 % % This file is encoded in UTF-8. Here is the euro symbol: % >> s = '€'; % >> disp(s) % € % >> disp(test_matlab_style_utf8()) % € % % % Its not our business how this is storied internally (its utf-8 % on Octave, not sure on Matlab). But we can convert explicitly % to utf-8: % >> nums = unicode2native(s, 'utf-8'); % >> double(nums) % 226 130 172 % Copyright (c) 2022-2023 Colin B. Macdonald % SPDX-License-Identifier: BSD-3-Clause s = '€'; end