function did_pass = cosmo_run_tests(varargin)
% run unit and documentation tests
%
% did_pass=cosmo_run_tests(['verbose',v]['output',fn])
%
% Inputs:
% '-verbose' run with verbose output
% '-logfile',fn store output in a file named fn (optional, if omitted
% output is written to the terminal window)
% 'file.m' run tests in 'file.m'
% '-no_doc_test' skip doctest
% '-no_unit_test' skip unittest
%
% Examples:
% % run tests with defaults
% cosmo_run_tests
%
% % run with non-verbose output
% cosmo_run_tests('verbose',false);
%
% % explicitly set verbose output and store output in file
% cosmo_run_tests('verbose',true,'output','~/mylogfile.txt');
%
% Notes:
% - Doctest functionality was inspired by T. Smith.
% - Unit tests can be run using MOxUnit by N.N. Oosterhof (2015-2017),
% https://github.com/MOxUnit/MOxUnit
% - Documentation tests can be run usxing MOdox by N.N. Oosterhof (2017),
% https://github.com/MOdox/MOdox
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
orig_pwd = pwd();
pwd_resetter = onCleanup(@()cd(orig_pwd));
[opt, test_locations, moxunit_args] = get_opt(varargin{:});
run_doctest = ~opt.no_doc_test;
run_unittest = ~opt.no_unit_test;
orig_path = path();
path_resetter = onCleanup(@()path(orig_path));
suite = MOxUnitTestSuite();
if run_doctest
doctest_suite = get_doctest_suite(test_locations);
suite = addFromSuite(suite, doctest_suite);
fprintf('doc test %s\n', str(doctest_suite));
end
if run_unittest
unittest_suite = get_unittest_suite(test_locations);
suite = addFromSuite(suite, unittest_suite);
fprintf('unit test %s\n', str(unittest_suite));
end
did_pass = moxunit_runtests(suite, moxunit_args{:});
function suite = get_doctest_suite(test_locations)
cosmo_check_external({'moxunit', 'modox'});
suite = MOdoxTestSuite();
suite = add_test_locations(suite, 'doc', test_locations);
function suite = get_unittest_suite(test_locations)
cosmo_check_external({'moxunit'});
suite = MOxUnitTestSuite();
suite = add_test_locations(suite, 'unit', test_locations);
function suite = add_test_locations(suite, type, test_locations)
if isempty(test_locations)
test_locations = {get_default_dir(type)};
prefix = get_default_prefix(type);
else
prefix = '';
end
pat = ['^' prefix '.*\.m$'];
for k = 1:numel(test_locations)
location = test_locations{k};
if isdir(location)
suite = addFromDirectory(suite, location, pat);
else
suite = addFromFile(suite, location);
end
end
function d = get_default_dir(name)
switch name
case 'root'
d = fileparts(fileparts(mfilename('fullpath')));
case 'unit'
d = fullfile(get_default_dir('root'), 'tests');
case 'doc'
d = fullfile(get_default_dir('root'), 'mvpa');
otherwise
assert(false);
end
function prefix = get_default_prefix(name)
s = struct();
s.unit = 'test_';
s.doc = 'cosmo_';
prefix = s.(name);
function [opt, test_locations, moxunit_args] = get_opt(varargin)
defaults = struct();
defaults.no_doc_test = false;
defaults.no_unit_test = false;
opt = defaults;
n_args = numel(varargin);
is_key_value_arg = {'-cover', ...
'-cover_xml_file', ...
'-cover_html_dir', ...
'-cover_json_file', ...
'-junit_xml_file', ...
'-cover_method', ...
'-partition_index', ...
'-partition_count', ...
'-logfile'};
test_locations = cell(n_args, 1);
moxunit_args = cell(n_args, 1);
k = 0;
while k < n_args
k = k + 1;
arg = varargin{k};
switch arg
case '-no_doc_test'
opt.no_doc_test = true;
case '-no_unit_test'
opt.no_unit_test = true;
otherwise
is_option = ~isempty(regexp(arg, '^-', 'once'));
if is_option
moxunit_args{k} = arg;
has_value = any(cellfun(@numel, ...
strfind(is_key_value_arg, arg)));
if has_value
if k == n_args
error('Missing value after key ''%s''', arg);
end
k = k + 1;
arg = varargin{k};
moxunit_args{k} = arg;
end
else
test_locations{k} = get_location(arg);
end
end
end
moxunit_args = remove_empty_from_cell(moxunit_args);
test_locations = remove_empty_from_cell(test_locations);
function ys = remove_empty_from_cell(xs)
keep = ~cellfun(@isempty, xs);
ys = xs(keep);
function full_path = get_location(location)
candidate_dirs = {'', ...
get_default_dir('unit'), ...
get_default_dir('doc')};
suffixes = {'', '.m'};
n_dirs = numel(candidate_dirs);
n_suffixes = numel(suffixes);
for k = 1:n_dirs
for j = 1:1:n_suffixes
fn = sprintf('%s%s', location, suffixes{j});
full_path = fullfile(candidate_dirs{k}, fn);
if exist(location, 'file')
return
end
end
end
error('Unable to find ''%s''', location);