let rec next_test_case conf logger state =
  match state.tests_planned, state.idle_workers with
    | [], _ ->
        Finished, state
    | _, worker :: tl_workers ->
        begin
          let choice =
            state.chooser
              {
                OUnitChooser.
                tests_planned = List.map fst state.tests_planned;
                tests_running = List.map fst state.tests_running;
                tests_passed = List.map fst state.tests_passed;
                cache = state.cache;
              }
          in
          match choice with
            | Choose test_path ->
                begin
                  try
                    let test_length, test_fun =
                      List.assoc test_path state.tests_planned
                    in
                    let now = OUnitUtils.now () in
                    Next_test_case (test_path, test_fun, worker),
                    {state with
                         tests_running =
                           (test_path,
                            {
                              test_length = test_length;
                              deadline = now +. delay_of_length test_length;
                              next_health_check =
                                now +. state.health_check_interval;
                              worker = worker;
                            }) :: state.tests_running;
                         tests_planned =
                           filter_out test_path state.tests_planned;
                         idle_workers =
                           tl_workers}
                  with Not_found ->
                    assert false
                end

            | ChooseToPostpone ->
                Try_again, state

            | ChooseToSkip path ->
                let skipped_result = RSkip "Skipped by the chooser." in
                  OUnitLogger.report logger (TestEvent (path, EStart));
                  OUnitLogger.report
                    logger (TestEvent (path, EResult skipped_result));
                  OUnitLogger.report logger (TestEvent (path, EEnd));
                  next_test_case
                    conf logger
                    (add_test_results conf
                       ((path, skipped_result, None), []) state)

            | NoChoice ->
                Finished, state

        end
    | _, [] ->
        Not_enough_worker, state