test external neuroelf

function test_suite = test_external_neuroelf()
    % regression tests for external "neuroelf" toolbox
    %
    % #   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_xff_map2fmri_map_no_increased_memory_usage()
    helper_test_xff_no_increased_memory_usage('map');

function test_xff_fmri_io_no_increased_memory_usage()
    helper_test_xff_no_increased_memory_usage('file');

function test_xff_map2fmri_object_no_increased_memory_usage()
    helper_test_xff_no_increased_memory_usage('object');

function helper_test_xff_no_increased_memory_usage(method)

    if cosmo_skip_test_if_no_external('neuroelf')
        return
    end

    n_orig = helper_count_xff_objects();

    ds = cosmo_synthetic_dataset();

    ext = 'vmp';
    switch method
        case 'file'
            fn = sprintf('%s.%s', tempname(), ext);
            cleaner = onCleanup(@()delete(fn));
            cosmo_map2fmri(ds, fn);

            n_new = helper_count_xff_objects();
            assert(n_new == n_orig, sprintf('count increased by %d', ...
                                            n_new - n_orig));

            ds_again = cosmo_fmri_dataset(fn);
            assertElementsAlmostEqual(sort(ds.samples(:)), ...
                                      sort(ds_again.samples(:)), 1e-5);
        case 'map'
            cosmo_map2fmri(ds, ['-bv_' ext]);

        case 'object'
            obj = cosmo_map2fmri(ds, ['-bv_' ext]);
            ds_again = cosmo_fmri_dataset(obj);

            % obj should not be cleared when mapping it
            assert(isfield(obj, 'XStart'));

            % cleanup
            clear ds_again;
            obj.ClearObject();
            clear obj;

        otherwise
            assert(false);
    end

    n_new = helper_count_xff_objects();
    assert(n_new == n_orig, sprintf('count increased by %d', n_new - n_orig));

function count = helper_count_xff_objects
    if cosmo_skip_test_if_no_external('!evalc')
        return
    end

    xff_str = evalc('xff()');
    lines = cosmo_strsplit(xff_str, '\n');

    pre_idx = strmatch('   # | Type  | ', lines);
    line_idxs = strmatch('------------------', lines);

    if isempty(pre_idx)
        % Neuroelf < v1.1, no objects
        assert(isempty(line_idxs));
        count = 0;
        return
    end

    post_idx = line_idxs(line_idxs > (pre_idx + 2));

    assert(numel(pre_idx) == 1);

    if numel(post_idx) == 0
        count = 0;
        return
    end

    assert(numel(post_idx) == 1);

    offset = 2;
    count = post_idx - pre_idx - offset;