function test_suite = test_parcellfun
% tests for cosmo_cartprod
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions=localfunctions();
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;
function test_parcellfun_single_proc()
nproc=1;
helper_test_parcellfun(nproc);
function test_cosmo_parallel_get_nproc_available()
warning_state=cosmo_warning();
cleaner=onCleanup(@()cosmo_warning(warning_state));
cosmo_warning('reset');
cosmo_warning('off');
nproc=cosmo_parallel_get_nproc_available();
assert(nproc>=1);
% should not have shown any warnings
w=cosmo_warning();
assert(isempty(w.shown_warnings),sprintf('warning shown: %s',...
w.shown_warnings{:}));
function test_parcellfun_multi_proc()
nproc=cosmo_parallel_get_nproc_available();
if nproc==1
cosmo_notify_test_skipped('No parallel process available');
return
end
helper_test_parcellfun(nproc);
function helper_test_parcellfun(nproc)
warning_state=cosmo_warning();
cleaner=onCleanup(@()cosmo_warning(warning_state));
cosmo_warning('off');
% try various functions
funcs={@func_identity,...
@func_reverse,...
@numel,...
@(x)numel(x)>0,...
};
% try with both uniform output and without
arg_cell={{},...
{'UniformOutput',false}};
% various number of dimensions
ndim={0,1,2,3,4}; % 0=empty
combis=cosmo_cartprod({funcs,arg_cell,ndim});
n=size(combis,1);
for c_i=1:n
combi=combis(c_i,:);
func_arg=combi{1};
other_arg=combi{2};
rand_str_ndim=combi{3};
rand_cellstr=generate_rand_cellstr(rand_str_ndim);
func=@()cosmo_parcellfun(nproc,func_arg,rand_cellstr,...
other_arg{:});
ref_func=@() cellfun(func_arg,rand_cellstr,other_arg{:});
assert_equal_result_or_both_exception_thrown(func,ref_func);
end
function assert_equal_result_or_both_exception_thrown(f, g)
try
f_result=f();
f_exception=false;
catch
f_exception=lasterror();
end
try
g_result=g();
g_exception=false;
catch
g_exception=lasterror();
end
f_threw_exception=isstruct(f_exception);
g_threw_exception=isstruct(g_exception);
if f_threw_exception
if ~g_threw_exception
f_exception.message=sprintf('only f threw exception: %s',...
f_exception.message);
rethrow(f_exception);
end
else
if g_threw_exception
g_exception.message=sprintf('only g threw exception: %s',...
g_exception.message);
rethrow(g_exception);
end
assertEqual(f_result,g_result);
end
function test_illegal_arguments
warning_state=cosmo_warning();
cleaner=onCleanup(@()cosmo_warning(warning_state));
cosmo_warning('off');
aet=@(varargin)assertExceptionThrown(@()...
cosmo_parcellfun(varargin{:}),'');
% first argument is not scalar integer
aet(0,@numel,{1,2});
aet(1.5,@numel,{1,2});
aet([2 3],@numel,{1,2});
% second argument is not a function handle
aet(2,'a',{1,2});
aet(2,cell(0),{1,2});
% third argument is not a cell
aet(2,@numel,[1,2]);
aet(2,@numel,struct);
% no uniform output
% (note: Octave accepts output when using
% @(x)[x x]
% This may be a bug)
aet(1,@(x) repmat(x,1,x),{1;2});
aet(2,@(x) repmat(x,1,x),{1;2});
function rand_cellstr=generate_rand_cellstr(ndim)
switch ndim
case 0
sz=[0,0];
case 1
sz=[0,10];
case 2
sz=[1,1];
otherwise
sz=floor(rand(1,1+ndim)*4);
end
randstr=@(unused)char(rand(1,floor(rand()*10))*24+65);
rand_cellstr=arrayfun(randstr,zeros(sz),'UniformOutput',false);
function y=func_identity(x)
y=x;
function y=func_reverse(x)
y=x;
y(end:-1:1)=x(:);