#!/bin/sh # Guard the MATLAB compatibility shims at image build time. # # Two jobs, both of which have to happen before anyone can run code # against this image rather than after: # # 1. DROP any shim whose name Octave has since acquired. The shim # directory sits ahead of everything on the path, so a stale copy # would shadow the real implementation - our four-signature `contains` # would quietly replace a complete one. Octave gaining a function is # good news; the correct response is to delete ours, not to keep it. # # 2. TEST what survives. Each shim is asserted against the behaviour the # MATLAB documentation specifies - including the edge conventions that # are the whole reason these are not one-line aliases. A failure fails # the build: a wrong answer that runs is the one outcome this sandbox # exists to prevent. # # print.m is exempt from (1). It shadows Octave's own print deliberately # and permanently; see shim/print.m. set -e SHIM_DIR=/opt/owuitools-shim [ -d "$SHIM_DIR" ] || { echo "check-shims: $SHIM_DIR missing"; exit 1; } for f in "$SHIM_DIR"/*.m; do name=$(basename "$f" .m) case "$name" in print|owuitools_*) continue ;; esac # Asked WITHOUT the shim directory on the path, which is where Octave # starts. The answer is printed rather than returned as an exit code, so # that an Octave that fails for some unrelated reason cannot be read as # "this function exists" - an unreadable answer keeps the shim, and the # behaviour tests below then have the last word. have=$(octave --no-window-system --norc --quiet \ --eval "printf('%d', exist('$name') > 0)" 2>/dev/null) case "$have" in 1) echo "check-shims: DROPPING $name - this Octave provides it" rm -f "$f" ;; 0) echo "check-shims: keeping $name (Octave has no such function)" ;; *) echo "check-shims: could not test $name (got '$have'), keeping it" ;; esac done echo "check-shims: running the behaviour tests" octave --no-window-system --norc --quiet --eval " addpath('$SHIM_DIR', '-begin'); function check(label, cond) if (~cond) error('check-shims FAILED: %s', label); end printf(' ok %s\n', label); end if (exist('contains') > 0) check('contains char', contains('hello world', 'o w') == true); check('contains miss', contains('hello', 'zz') == false); check('contains cell', isequal(contains({'ab','cd'}, 'c'), [false true])); check('contains any of', contains('abc', {'x','b'}) == true); check('contains IgnoreCase', contains('ABC', 'b', 'IgnoreCase', true) == true); end if (exist('strlength') > 0) check('strlength char', strlength('abcd') == 4); check('strlength cell', isequal(strlength({'a','abc'}), [1 3])); check('strlength empty', strlength('') == 0); end if (exist('matches') > 0) check('matches exact', matches('abc', 'abc') == true); check('matches not substring', matches('abc', 'ab') == false); end if (exist('maxk') > 0) check('maxk values', isequal(maxk([3 1 4 1 5], 2), [5 4])); check('maxk row shape', size(maxk([3 1 4], 2), 1) == 1); [~, i] = maxk([3 1 4 1 5], 2); check('maxk indices', isequal(i, [5 3])); check('maxk k over n', numel(maxk([1 2], 9)) == 2); check('maxk matrix is column-wise', isequal(maxk([1 9; 5 2], 1), [5 9])); end if (exist('mink') > 0) check('mink values', isequal(mink([3 1 4 1 5], 2), [1 1])); end if (exist('histcounts') > 0) check('histcounts counts', isequal(histcounts([1 2 2 3], [1 2 3 4]), [1 2 1])); check('histcounts last bin closed', isequal(histcounts([4], [1 2 3 4]), [0 0 1])); check('histcounts half open', isequal(histcounts([2], [1 2 3 4]), [0 1 0])); check('histcounts drops NaN', sum(histcounts([1 NaN], [1 2])) == 1); failed = false; try histcounts([1 2 3]); catch failed = true; end check('histcounts refuses auto bins', failed); end if (exist('discretize') > 0) check('discretize bins', isequal(discretize([1 2.5 4], [1 2 3 4]), [1 2 3])); check('discretize outside is NaN', isnan(discretize(9, [1 2]))); end if (exist('rmmissing') > 0) check('rmmissing vector', isequal(rmmissing([1 NaN 3]), [1 3])); check('rmmissing keeps row shape', size(rmmissing([1 NaN 3]), 1) == 1); check('rmmissing matrix drops rows', isequal(rmmissing([1 2; NaN 4; 5 6]), [1 2; 5 6])); failed = false; try rmmissing({'a'}); catch failed = true; end check('rmmissing refuses cells', failed); end printf('check-shims: all shim behaviour tests pass\n'); "