public void assertWorkingScoreFromScratch(Score workingScore, Object completedAction) { ScoreDirectorFactory assertionScoreDirectorFactory = scoreDirectorFactory.getAssertionScoreDirectorFactory(); if (assertionScoreDirectorFactory == null) { assertionScoreDirectorFactory = scoreDirectorFactory; } ScoreDirector uncorruptedScoreDirector = assertionScoreDirectorFactory.buildScoreDirector(); uncorruptedScoreDirector.setWorkingSolution(workingSolution); Score uncorruptedScore = uncorruptedScoreDirector.calculateScore(); if (!workingScore.equals(uncorruptedScore)) { String scoreCorruptionAnalysis = buildScoreCorruptionAnalysis(uncorruptedScoreDirector); uncorruptedScoreDirector.dispose(); throw new IllegalStateException( "Score corruption: the workingScore (" + workingScore + ") is not the uncorruptedScore (" + uncorruptedScore + ") after completedAction (" + completedAction + "):\n" + scoreCorruptionAnalysis); } else { uncorruptedScoreDirector.dispose(); } }
/** * @param uncorruptedScoreDirector never null * @return never null */ protected String buildScoreCorruptionAnalysis(ScoreDirector uncorruptedScoreDirector) { if (!isConstraintMatchEnabled() || !uncorruptedScoreDirector.isConstraintMatchEnabled()) { return " Score corruption analysis could not be generated because" + " either corrupted constraintMatchEnabled (" + isConstraintMatchEnabled() + ") or uncorrupted constraintMatchEnabled (" + uncorruptedScoreDirector.isConstraintMatchEnabled() + ") is disabled.\n" + " Check your score constraints manually."; } Collection<ConstraintMatchTotal> corruptedConstraintMatchTotals = getConstraintMatchTotals(); Collection<ConstraintMatchTotal> uncorruptedConstraintMatchTotals = uncorruptedScoreDirector.getConstraintMatchTotals(); Map<List<Object>, ConstraintMatch> corruptedMap = createConstraintMatchMap(corruptedConstraintMatchTotals); Map<List<Object>, ConstraintMatch> excessMap = new LinkedHashMap<List<Object>, ConstraintMatch>(corruptedMap); Map<List<Object>, ConstraintMatch> missingMap = createConstraintMatchMap(uncorruptedConstraintMatchTotals); excessMap.keySet().removeAll(missingMap.keySet()); // missingMap == uncorruptedMap missingMap.keySet().removeAll(corruptedMap.keySet()); final int CONSTRAINT_MATCH_DISPLAY_LIMIT = 8; StringBuilder analysis = new StringBuilder(); if (excessMap.isEmpty()) { analysis.append( " The corrupted scoreDirector has no ConstraintMatch(s) which are in excess.\n"); } else { analysis .append(" The corrupted scoreDirector has ") .append(excessMap.size()) .append(" ConstraintMatch(s) which are in excess (and should not be there):\n"); int count = 0; for (ConstraintMatch constraintMatch : excessMap.values()) { if (count >= CONSTRAINT_MATCH_DISPLAY_LIMIT) { analysis .append(" ... ") .append(excessMap.size() - CONSTRAINT_MATCH_DISPLAY_LIMIT) .append(" more\n"); break; } analysis.append(" ").append(constraintMatch).append("\n"); count++; } } if (missingMap.isEmpty()) { analysis.append( " The corrupted scoreDirector has no ConstraintMatch(s) which are missing.\n"); } else { analysis .append(" The corrupted scoreDirector has ") .append(missingMap.size()) .append(" ConstraintMatch(s) which are missing:\n"); int count = 0; for (ConstraintMatch constraintMatch : missingMap.values()) { if (count >= CONSTRAINT_MATCH_DISPLAY_LIMIT) { analysis .append(" ... ") .append(missingMap.size() - CONSTRAINT_MATCH_DISPLAY_LIMIT) .append(" more\n"); break; } analysis.append(" ").append(constraintMatch).append("\n"); count++; } } if (excessMap.isEmpty() && missingMap.isEmpty()) { analysis .append( " The corrupted scoreDirector has no ConstraintMatch(s) in excess or missing." + " That could be a bug in this class (") .append(getClass()) .append(").\n"); } appendLegacyConstraintOccurrences(analysis, this, uncorruptedScoreDirector); analysis.append(" Check your score constraints."); return analysis.toString(); }