/**
   * {@inheritDoc}
   *
   * <p>Execute all tests and count covered branches
   */
  @Override
  public double getFitness(AbstractTestSuiteChromosome<? extends ExecutableChromosome> suite) {
    logger.trace("Calculating branch fitness");
    double fitness = 0.0;

    List<ExecutionResult> results = runTestSuite(suite);
    Map<Integer, Double> trueDistance = new HashMap<Integer, Double>();
    Map<Integer, Double> falseDistance = new HashMap<Integer, Double>();
    Map<Integer, Integer> predicateCount = new HashMap<Integer, Integer>();

    // Collect stats in the traces
    boolean hasTimeoutOrTestException =
        analyzeTraces(suite, results, predicateCount, trueDistance, falseDistance);

    // Collect branch distances of covered branches
    int numCoveredBranches = 0;

    for (Integer key : predicateCount.keySet()) {

      double df = 0.0;
      double dt = 0.0;
      int numExecuted = predicateCount.get(key);

      if (removedBranchesT.contains(key)) numExecuted++;
      if (removedBranchesF.contains(key)) numExecuted++;

      if (trueDistance.containsKey(key)) {
        dt = trueDistance.get(key);
      }
      if (falseDistance.containsKey(key)) {
        df = falseDistance.get(key);
      }
      // If the branch predicate was only executed once, then add 1
      if (numExecuted == 1) {
        fitness += 1.0;
      } else {
        fitness += normalize(df) + normalize(dt);
      }

      if (falseDistance.containsKey(key) && (Double.compare(df, 0.0) == 0)) numCoveredBranches++;

      if (trueDistance.containsKey(key) && (Double.compare(dt, 0.0) == 0)) numCoveredBranches++;
    }

    // +1 for every branch that was not executed
    fitness += 2 * (totalBranches - predicateCount.size());

    printStatusMessages(suite, numCoveredBranches, fitness);

    // Calculate coverage
    int coverage = numCoveredBranches;

    coverage += removedBranchesF.size();
    coverage += removedBranchesT.size();

    if (totalGoals > 0) suite.setCoverage(this, (double) coverage / (double) totalGoals);
    else suite.setCoverage(this, 1);

    suite.setNumOfCoveredGoals(this, coverage);
    suite.setNumOfNotCoveredGoals(this, totalGoals - coverage);

    if (hasTimeoutOrTestException) {
      logger.info("Test suite has timed out, setting fitness to max value " + (totalBranches * 2));
      fitness = totalBranches * 2;
      // suite.setCoverage(0.0);
    }

    updateIndividual(this, suite, fitness);

    assert (coverage <= totalGoals) : "Covered " + coverage + " vs total goals " + totalGoals;
    assert (fitness >= 0.0);
    assert (fitness != 0.0 || coverage == totalGoals)
        : "Fitness: " + fitness + ", " + "coverage: " + coverage + "/" + totalGoals;
    assert (suite.getCoverage(this) <= 1.0) && (suite.getCoverage(this) >= 0.0)
        : "Wrong coverage value " + suite.getCoverage(this);
    return fitness;
  }