classdef TestRunner < handle

  properties

    testcases = {};

  end % properties

  methods

    function self = TestRunner(testcases)
      self.testcases = testcases;
    end
    
    function results = run(self)

      failures = {};

      for kk = 1:numel(self.testcases)

        % instance
        t = feval(self.testcases{kk});

        % setup class
        t.setUpClass();
        cleanclass = onCleanup(@()t.tearDownClass());

        for m = t.listTests()

          try
            % setup test
            t.setUp()
            clean = onCleanup(@()t.tearDown());
          catch ex
            % something went wrong in test setup code
            fprintf('E');
          end

          try
            % run test
            feval(m{1}, t);
            fprintf('.');
          catch ex
            % test failure
            fprintf('F');
            failures = [ failures { {self.testcases{kk} m{1} ex } }];
          end
          % explicitly call cleanup handler
          clear clean;
        end
        % explicitly call class cleanup handler
        clear cleanclass;
      end
      fprintf('\n');

      self.reportFailures(failures)

    end

    function reportFailures(self, failures)
      for kk = 1:numel(failures)
        f = failures{kk};
        fprintf(2, '%s: %s: %s\n%s', which(f{1}), f{1}, f{2}, f{3}.getReport());
      end
    end

  end % methods

end
