test disp

function test_suite = test_disp
    % tests for cosmo_disp
    %
    % #   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_disp_array()
    if ~has_evalc()
        cosmo_notify_test_skipped('No support for ''evalc''');
        return
    end

    aeq = @(s, y) assertEqual([s repmat(sprintf('\n'), size(s, 1), 1)], ...
                              evalc('cosmo_disp(y)'));

    aeq(['[ 1         2         3  ...  '...
         '8         9        10 ]@1x10'], 1:10);

function test_disp_struct()
    if ~has_evalc()
        cosmo_notify_test_skipped('No support for ''evalc''');
        return
    end

    aeq = @(s, y) assertEqual([s repmat(sprintf('\n'), size(s, 1), 1)], ...
                              evalc('cosmo_disp(y)'));

    x = struct();
    x.a_cell = {[], {'cell in cell', [1 2; 3 4]}};
    x.a_matrix = [10 11 12; 13 14 15];
    x.a_string = 'hello world';
    x.a_struct.another_struct.name = 'me';

    s = sprintf(['.a_cell                                        \n'...
                 '  { [  ]  { ''cell in cell''  [ 1         2      \n'...
                 '                              3         4 ] } }\n'...
                 '.a_matrix                                      \n'...
                 '  [ 10        11        12                     \n'...
                 '    13        14        15 ]                   \n'...
                 '.a_string                                      \n'...
                 '  ''hello world''                                \n'...
                 '.a_struct                                      \n'...
                 '  .another_struct                              \n'...
                 '    .name                                      \n'...
                 '      ''me''                                     ']);

    aeq(s, x);

function test_disp_cases
    if ~has_evalc
        cosmo_notify_test_skipped('No support for ''evalc''');
        return
    end

    x = 1:5;
    assert_equal_disp(x, 'threshold', Inf, ...
                      '[ 1         2         3         4         5 ]\n' ...
                     );

    x = 1:5;
    assert_equal_disp(x, 'edgeitems', 2, 'threshold', 1, ...
                      '[ 1         2  ...  4         5 ]@1x5\n' ...
                     );

    x = 1:5;
    assert_equal_disp(x, 'edgeitems', 1, 'threshold', 2, ...
                      '[ 1  ...  5 ]@1x5\n' ...
                     );

    x = 1:5;
    assert_equal_disp(x, 'edgeitems', 3, ...
                      '[ 1         2         3         4         5 ]\n' ...
                     );

    x = 'a':'z';
    assert_equal_disp(x, ...
                      '''abcdefg ... tuvwxyz''\n' ...
                     );

    x = @abs;
    assert_equal_disp(x, ...
                      '@abs\n' ...
                     );

    x = {{1, 2}};
    assert_equal_disp(x, 'depth', 1, ...
                      '{ <cell>@1x2 }\n' ...
                     );

    x = [13e-20, pi(), 13e20];
    assert_equal_disp(x, ...
                      '[ 1.3e-19      3.14   1.3e+21 ]\n' ...
                     );

    x = [13e-20, pi(), 13e20];
    assert_equal_disp(x, 'precision', 5, ...
                      '[ 1.3e-19      3.1416     1.3e+21 ]\n' ...
                     );

    x = struct();
    y = x([]);
    assert_equal_disp(y, ...
                      'struct (empty)\n' ...
                     );

    x = struct('x', 1);
    assert_equal_disp(x, ...
                      ['.x     \n'...
                       '  [ 1 ]\n' ...
                      ]);

    x = struct('x', {1 2; 3 4});
    assert_equal_disp(x, ...
                      ['<struct>@2x2   \n'...
                       '   (1,1).x     \n'...
                       '          [ 1 ]\n'...
                       '   (2,1).x     \n'...
                       '          [ 3 ]\n'...
                       '   (1,2).x     \n'...
                       '          [ 2 ]\n'...
                       '   (2,2).x     \n'...
                       '          [ 4 ]\n' ...
                      ]);

    x = struct('x', {1 2; 3 4});
    x3 = cat(3, x, x, x);
    assert_equal_disp(x3, ...
                      ['<struct>@2x2x3   \n'...
                       '   (1,1,1).x     \n'...
                       '            [ 1 ]\n'...
                       '   (2,1,1).x     \n'...
                       '            [ 3 ]\n'...
                       '   (1,2,1).x     \n'...
                       '            [ 2 ]\n'...
                       '     :        :  \n'...
                       '   (2,1,3).x     \n'...
                       '            [ 3 ]\n'...
                       '   (1,2,3).x     \n'...
                       '            [ 2 ]\n'...
                       '   (2,2,3).x     \n'...
                       '            [ 4 ]\n' ...
                      ]);

    x = struct('x', {1 2; 3 4});
    y = repmat({x}, 10, 10);
    x3 = cat(3, y{:});
    assert_equal_disp(x3, ...
                      ['<struct>@2x2x100   \n'...
                       '   (1,1,1)  .x     \n'...
                       '              [ 1 ]\n'...
                       '   (2,1,1)  .x     \n'...
                       '              [ 3 ]\n'...
                       '   (1,2,1)  .x     \n'...
                       '              [ 2 ]\n'...
                       '      :         :  \n'...
                       '   (2,1,100).x     \n'...
                       '              [ 3 ]\n'...
                       '   (1,2,100).x     \n'...
                       '              [ 2 ]\n'...
                       '   (2,2,100).x     \n'...
                       '              [ 4 ]\n' ...
                      ]);

    x = zeros([2 2 1 2 3]);
    x(:) = 2 * (1:numel(x));
    assert_equal_disp(x, ...
                      ['<double>@2x2x1x2x3               \n'...
                       '   (:,:,1,1,1) = [ 2         6   \n'...
                       '                   4         8 ] \n'...
                       '   (:,:,1,2,1) = [ 10        14  \n'...
                       '                   12        16 ]\n'...
                       '   (:,:,1,1,2) = [ 18        22  \n'...
                       '                   20        24 ]\n'...
                       '   (:,:,1,2,2) = [ 26        30  \n'...
                       '                   28        32 ]\n'...
                       '   (:,:,1,1,3) = [ 34        38  \n'...
                       '                   36        40 ]\n'...
                       '   (:,:,1,2,3) = [ 42        46  \n'...
                       '                   44        48 ]\n' ...
                      ]);

    x = num2cell(1:10);
    assert_equal_disp(x, ...
                      '{ [ 1 ]  [ 2 ]  [ 3 ] ... [ 8 ]  [ 9 ]  [ 10 ]   }@1x10\n' ...
                     );

    x = reshape(num2cell(1:100), 10, 10);
    assert_equal_disp(x, ...
                      ['{ [ 1 ]   [ 11 ]  [ 21 ] ... [ 71 ]  [ 81 ]  [ 91 ]           \n'...
                       '  [ 2 ]   [ 12 ]  [ 22 ] ... [ 72 ]  [ 82 ]  [ 92 ]           \n'...
                       '  [ 3 ]   [ 13 ]  [ 23 ] ... [ 73 ]  [ 83 ]  [ 93 ]           \n'...
                       '    :       :       :          :       :       :              \n'...
                       '  [ 8 ]   [ 18 ]  [ 28 ] ... [ 78 ]  [ 88 ]  [ 98 ]           \n'...
                       '  [ 9 ]   [ 19 ]  [ 29 ] ... [ 79 ]  [ 89 ]  [ 99 ]           \n'...
                       '  [ 10 ]  [ 20 ]  [ 30 ] ... [ 80 ]  [ 90 ]  [ 100 ]   }@10x10\n' ...
                      ]);

    x = reshape(1:100, 10, 10);
    assert_equal_disp(x, ...
                      ['[  1        11        21  ...  71        81        91        \n'...
                       '   2        12        22  ...  72        82        92        \n'...
                       '   3        13        23  ...  73        83        93        \n'...
                       '   :         :         :        :         :        :         \n'...
                       '   8        18        28  ...  78        88        98        \n'...
                       '   9        19        29  ...  79        89        99        \n'...
                       '  10        20        30  ...  80        90       100 ]@10x10\n' ...
                      ]);

function test_disp_nosize()
    if ~has_evalc() || cosmo_wtf('is_octave')
        cosmo_notify_test_skipped(['No support for testing evalc '...
                                   'on data with no size']);
        return
    end
    orig_pwd = pwd();
    pwd_resetter = onCleanup(@()cd(orig_pwd));
    temp_dir = fullfile(orig_pwd, cosmo_make_temp_filename());
    dir_cleaner = onCleanup(@()remove_dir_helper(temp_dir));

    % override 'size' method for double
    mkdir(temp_dir);
    temp_double_dir = fullfile(temp_dir, '@double');
    mkdir(temp_double_dir);

    size_fn = fullfile(temp_double_dir, 'size.m');
    fid = fopen(size_fn, 'w');
    fprintf(fid, 'function size(varargin)\nerror(''undefined'');');
    fclose(fid);

    cd(temp_dir);
    assert_equal_disp(1, '<double>\n');

function tf = has_evalc()
    tf = exist('evalc', 'builtin') || ~isempty(which('evalc'));

function remove_dir_helper(tmp_dir)
    if cosmo_wtf('is_octave')
        rmdir_state = confirm_recursive_rmdir();
        state_resetter = onCleanup(@()confirm_recursive_rmdir(rmdir_state));
        confirm_recursive_rmdir(false, 'local');
    end
    rmdir(tmp_dir, 's');

function assert_equal_disp(varargin)
    args = varargin(1:(end - 1));
    str = varargin{end};

    cmd = 'cosmo_disp(args{:})';
    assertEqual(evalc(cmd), sprintf(str));