function [passed,results] = run_tbx_tests(test_case,coverage_report)
% Test runner for generic toolbox tests

if nargin==0 || isempty(test_case)
  test_case = 'basic'; % default
end

if nargin < 2
  coverage_report = false; % default
end

if coverage_report
  assert(~verLessThan('matlab','9.6.0'),'coverage_report=true needs MATLAB 9.6.0 or later');
  assert( strcmpi(test_case,'coverage'),'coverage_report=true should only be used with test_case=''coverage''');
end

needXML=~isempty(getenv('GITLAB_CI')) && ~verLessThan('matlab','8.6.0');
needCOV=~isempty(getenv('GITLAB_CI')) && ~verLessThan('matlab','9.6.0') || coverage_report;

%% Default outputs
passed=false; results=[]; % default outputs

%% Import some classes we need
if verLessThan('matlab','8.5.0')
  assert(ismember(lower(test_case),{'all','coverage'}),'test_case should be ''all'' or ''coverage'' for MATLAB 8.4.0 or earlier');
else
  import matlab.unittest.selectors.HasTag;
end
if needXML
  import matlab.unittest.plugins.XMLPlugin;
end

%% Paths
% add path of toolbox to make sure it is in the path
tbxpath = fileparts(mfilename('fullpath'));
addpath(tbxpath); % add default path
projectpath = getenv('CI_PROJECT_DIR');
if isempty(projectpath), projectpath = tbxpath; end

% add additional paths present in a local setpaths_* file
setpathsfile = dir(fullfile(tbxpath,'setpaths_*'));
if numel(setpathsfile)==1
  fname = fullfile(tbxpath,setpathsfile.name);
  fprintf('adding extra paths by calling %s\n',fname);
  run(fname); % run file to add paths
elseif numel(setpathsfile)>1
  error('multiple setpaths_* files found!');
end

%% Name
tbxname = getenv('TBXTARGET');
if isempty(tbxname)
  % Fallback value: name of folder
  [~,tbxname] = fileparts(tbxpath);
end

%% Generate test suite
testspath = fullfile(tbxpath,'tests');

lastwarn('','');
suite_all = matlab.unittest.TestSuite.fromFolder(testspath);
[~,s] = lastwarn();
if isequal(s,'MATLAB:unittest:TestSuite:FileExcluded')
  fprintf('File excluded during test suite creation - possible syntax errors in a test class');
  return
end
 
switch lower(test_case)
  case {'all','coverage'}
    suite = suite_all; % run all
  case 'basic'
    s = ~HasTag('slow');
    suite = suite_all.selectIf(s);
  otherwise
    s = HasTag(test_case);
    suite = suite_all.selectIf(s);
end

if isempty(suite)
  fprintf('\nEmpty test suite returned for TestTag=''%s''\n',test_case); return;
end

%% run it
fprintf('Start test case: %s\n%s\n\n',test_case,datestr(now));
runner = matlab.unittest.TestRunner.withTextOutput;
if needXML || needCOV
  prefix = sprintf('test_%s',tbxname);
  suffix = version('-release');
end
if needXML
  % Add some JUnit XML file with tests results
  xmlFile = fullfile(projectpath,sprintf('%s_%s_%s.xml',prefix,test_case,suffix));
  fprintf('\tGenerating JUnit XML report at %s\n',xmlFile);
  p = XMLPlugin.producingJUnitFormat(xmlFile);
  runner.addPlugin(p)
end
if needCOV
  % Add some code coverage report
  switch lower(test_case)
    case 'coverage'
      % Produce HTML report
      reportFolder = fullfile(projectpath,sprintf('%s_%s_cov',prefix,suffix));
      reportFormat = matlab.unittest.plugins.codecoverage.CoverageReport(reportFolder);
    otherwise
      % Produce XML file in Cobertura format (for Gitlab MR viz.)
      xmlFile = fullfile(projectpath,sprintf('%s_%s_%s_cov.xml',prefix,test_case,suffix));
      reportFormat = matlab.unittest.plugins.codecoverage.CoberturaFormat(xmlFile);
  end
  p = matlab.unittest.plugins.CodeCoveragePlugin.forFolder(fileparts(mfilename('fullpath')),...
    'IncludingSubfolders',true,'Producing',reportFormat);
  runner.addPlugin(p)
end
results = runner.run(suite);
if ~verLessThan('matlab','8.4.0')
  disp(table(results));
end
fprintf('\nTotal test duration: %5.2fs\n',sum([results.Duration]));

if all([results.Passed])
  fprintf('\nPassed all tests\n')
  passed = true;
elseif any([results.Failed])
  fprintf('\nSome tests Failed\n')
  if ~verLessThan('matlab','8.4.0')
    disp(table(results([results.Failed])))
  end
  passed = false;
elseif any([results.Incomplete])
  fprintf('\nSome tests Incomplete\n')
  if ~verLessThan('matlab','8.4.0')
    disp(table(results([results.Incomplete])));
  end
  passed = true; % pass tests even if some were skipped
else
  % the conditions above should cover all cases, otherwise 
  error('something is very wrong - please check')
end

end
