From 81a1cfb83fd7fe2c1b69b61354e886a8157a634d Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Mon, 8 Jul 2019 16:43:03 +0200
Subject: [PATCH] OO-4130: Average of each heat map row

---
 .../analysis/QualityAnalysisService.java      | 14 ++++-
 .../analysis/manager/AnalysisFilterDAO.java   |  2 +-
 .../manager/QualityAnalysisServiceImpl.java   | 10 +++-
 .../manager/StatisticsCalculator.java         | 44 ++++++++++++++-
 .../analysis/ui/AnalysisUIFactory.java        |  2 +-
 .../analysis/ui/FooterGroupByDataModel.java   |  8 ++-
 .../analysis/ui/GroupByController.java        | 12 +++-
 .../quality/analysis/ui/GroupByDataModel.java |  3 +
 .../quality/analysis/ui/GroupByRow.java       | 13 +++++
 .../analysis/ui/HeatMapController.java        | 55 ++++++++++++++++++-
 .../quality/analysis/ui/TrendController.java  |  5 ++
 .../ui/_i18n/LocalStrings_de.properties       |  1 +
 .../ui/_i18n/LocalStrings_en.properties       |  1 +
 .../manager/StatisticsCalculatorTest.java     | 46 +++++++++++++++-
 14 files changed, 202 insertions(+), 14 deletions(-)

diff --git a/src/main/java/org/olat/modules/quality/analysis/QualityAnalysisService.java b/src/main/java/org/olat/modules/quality/analysis/QualityAnalysisService.java
index 47481ac66c0..8dc5a5f3087 100644
--- a/src/main/java/org/olat/modules/quality/analysis/QualityAnalysisService.java
+++ b/src/main/java/org/olat/modules/quality/analysis/QualityAnalysisService.java
@@ -113,7 +113,19 @@ public interface QualityAnalysisService {
 	public MultiTrendSeries<MultiKey> calculateTrends(AnalysisSearchParameter searchParams,
 			Set<Rubric> rubrics, MultiGroupBy groupBy, TemporalGroupBy temporalGroupBy);
 	
-	public HeatMapStatistic calculateTotal(List<HeatMapStatistic> statistics, Rubric rubric);
+	/**
+	 * Calculate the statistic for all sliders of all rubrics. Before using this method, make sure,
+	 * that all rubrics are identically configured to get accurate results (same
+	 * scale, number of steps, good end, ...)!
+	 *
+	 * @param statistics
+	 * @param rubrics
+	 * @return
+	 */
+	public HeatMapStatistic calculateRubricsTotal(List<? extends GroupedStatistic> statistics, Collection<Rubric> rubrics);
+	
+	public HeatMapStatistic calculateSliderTotal(List<? extends HeatMapStatistic> statistics, Rubric rubric);
 
 	public boolean isInsufficient(Rubric rubric, Double avg);
+
 }
diff --git a/src/main/java/org/olat/modules/quality/analysis/manager/AnalysisFilterDAO.java b/src/main/java/org/olat/modules/quality/analysis/manager/AnalysisFilterDAO.java
index c393944bbf2..3e87dbaceff 100644
--- a/src/main/java/org/olat/modules/quality/analysis/manager/AnalysisFilterDAO.java
+++ b/src/main/java/org/olat/modules/quality/analysis/manager/AnalysisFilterDAO.java
@@ -393,7 +393,7 @@ public class AnalysisFilterDAO {
 		sb.append(groupByIdentifier? " response.responseIdentifier": " cast(null as string)");
 		appendGroupBys(sb, multiGroupBy, true);
 		appendTemporalGroupBy(sb, temporalGroupBy, true);
-		sb.append("     , count(response)");
+		sb.append("     , count(distinct response.key)");
 		sb.append("     , avg(response.numericalResponse)");
 		sb.append("       )");
 		appendFrom(sb, searchParams);
diff --git a/src/main/java/org/olat/modules/quality/analysis/manager/QualityAnalysisServiceImpl.java b/src/main/java/org/olat/modules/quality/analysis/manager/QualityAnalysisServiceImpl.java
index 06540c9222d..6ebb07fa0f1 100644
--- a/src/main/java/org/olat/modules/quality/analysis/manager/QualityAnalysisServiceImpl.java
+++ b/src/main/java/org/olat/modules/quality/analysis/manager/QualityAnalysisServiceImpl.java
@@ -344,8 +344,14 @@ public class QualityAnalysisServiceImpl implements QualityAnalysisService {
 	}
 
 	@Override
-	public HeatMapStatistic calculateTotal(List<HeatMapStatistic> statistics, Rubric rubric) {
-		return statisticsCalculator.calculateTotal(statistics, rubric);
+	public HeatMapStatistic calculateRubricsTotal(List<? extends GroupedStatistic> statistics,
+			Collection<Rubric> rubric) {
+		return statisticsCalculator.calculateRubricsTotal(statistics, rubric);
+	}
+
+	@Override
+	public HeatMapStatistic calculateSliderTotal(List<? extends HeatMapStatistic> statistics, Rubric rubrics) {
+		return statisticsCalculator.calculateSliderTotal(statistics, rubrics);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
index e748e277d47..0477c37ae55 100644
--- a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
+++ b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
@@ -115,8 +115,50 @@ public class StatisticsCalculator {
 		log.debug("Grouped statistic:        " + statistic.toString());
 		return statistic;
 	}
+
+	public HeatMapStatistic calculateRubricsTotal(List<? extends GroupedStatistic> statistics,
+			Collection<Rubric> rubrics) {
+		Rubric firstRubric = null;
+		HeatMapStatistic total;
+		long count = 0;
+		long sumCount = 0;
+		double sumValues = 0;
+		for (Rubric rubric: rubrics) {
+			if (firstRubric == null) {
+				firstRubric = rubric;
+			}
+			for (Slider slider: rubric.getSliders()) {
+				GroupedStatistic statistic = getStatistic(statistics, slider);
+				if (statistic != null) {
+					Long statisticCount = statistic.getCount();
+					if (statisticCount != null) {
+						count += statisticCount.longValue();
+						sumCount += statisticCount.longValue() * slider.getWeight().intValue();
+						sumValues += statisticCount.longValue() * statistic.getAvg().doubleValue() * slider.getWeight().intValue();
+					}
+				}
+			}
+		}
+		if (count == 0) {
+			total = new HeatMapStatisticImpl(null, null, null);
+		} else {
+			double avg = sumValues / sumCount;
+			RubricRating rating = evaluationFormManager.getRubricRating(firstRubric, avg);
+			total = new HeatMapStatisticImpl(count, avg, rating);
+		}
+		return total;
+	}
 	
-	HeatMapStatistic calculateTotal(List<HeatMapStatistic> statistics, Rubric rubric) {
+	private GroupedStatistic getStatistic(List<? extends GroupedStatistic> statistics, Slider slider) {
+		for (GroupedStatistic statistic : statistics) {
+			if (statistic != null && slider.getId().equals(statistic.getIdentifier())) {
+				return statistic;
+			}
+		}
+		return null;
+	}
+
+	HeatMapStatistic calculateSliderTotal(List<? extends HeatMapStatistic> statistics, Rubric rubric) {
 		HeatMapStatistic total;
 		long count = 0;
 		double sumValues = 0;
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/AnalysisUIFactory.java b/src/main/java/org/olat/modules/quality/analysis/ui/AnalysisUIFactory.java
index 7cfcdd7274c..a282164c800 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/AnalysisUIFactory.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/AnalysisUIFactory.java
@@ -210,7 +210,7 @@ class AnalysisUIFactory {
 		return keyValues;
 	}
 	
-	private static boolean areIdenticalRubrics(List<Rubric> rubrics) {
+	static boolean areIdenticalRubrics(List<Rubric> rubrics) {
 		Rubric master = rubrics.get(0);
 		for (int i = 1; i < rubrics.size(); i++) {
 			Rubric rubric = rubrics.get(i);
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/FooterGroupByDataModel.java b/src/main/java/org/olat/modules/quality/analysis/ui/FooterGroupByDataModel.java
index e578b5c2464..c297faa48ce 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/FooterGroupByDataModel.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/FooterGroupByDataModel.java
@@ -25,6 +25,7 @@ import java.util.Locale;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableFooterModel;
+import org.olat.modules.quality.analysis.HeatMapStatistic;
 
 /**
  * 
@@ -36,15 +37,17 @@ class FooterGroupByDataModel extends GroupByDataModel implements FlexiTableFoote
 	
 	private final String footerHeader;
 	private List<?> footerDataValues;
+	private Object footerTotal;
 
 	FooterGroupByDataModel(FlexiTableColumnModel columnsModel, Locale locale, String footerHeader) {
 		super(columnsModel, locale);
 		this.footerHeader = footerHeader;
 	}
 	
-	public void setObjects(List<GroupByRow> objects, List<?> footerDataValues) {
+	public void setObjects(List<GroupByRow> objects, List<?> footerDataValues, HeatMapStatistic footerTotal) {
 		super.setObjects(objects);
 		this.footerDataValues = footerDataValues;
+		this.footerTotal = footerTotal;
 	}
 	
 	@Override
@@ -63,6 +66,9 @@ class FooterGroupByDataModel extends GroupByDataModel implements FlexiTableFoote
 			int pos = col - GroupByController.DATA_OFFSET;
 			return footerDataValues.get(pos);
 		}
+		if (col == GroupByController.TOTAL_OFFSET) {
+			return footerTotal;
+		}
 		return null;
 	}
 
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByController.java b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByController.java
index 7d2538f032a..5054e6f17f0 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByController.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByController.java
@@ -98,7 +98,8 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public abstract class GroupByController extends FormBasicController implements FilterableController {
 
-	public static final int DATA_OFFSET = 10;
+	public static final int TOTAL_OFFSET = 99;
+	public static final int DATA_OFFSET = 100;
 	
 	private static final String CMD_GROUP_PREFIX = "CLICKED_";
 	private static final String CMD_TREND = "TREND";
@@ -106,7 +107,7 @@ public abstract class GroupByController extends FormBasicController implements F
 	private static final Collection<GroupBy> GROUP_BY_TOPICS = Arrays.asList(GroupBy.TOPIC_IDENTITY,
 			GroupBy.TOPIC_ORGANISATION, GroupBy.TOPIC_CURRICULUM, GroupBy.TOPIC_CURRICULUM_ELEMENT,
 			GroupBy.TOPIC_REPOSITORY);
-	
+
 	private TooledStackedPanel stackPanel;
 	private ToolComponents toolComponents;
 	private FormLayoutContainer groupingCont;
@@ -255,6 +256,8 @@ public abstract class GroupByController extends FormBasicController implements F
 
 	protected abstract Set<MultiKey> getStatisticsMultiKeys();
 	
+	protected abstract void addTotalDataColumn(FlexiTableColumnModel columnsModel, int columnIndex);
+	
 	protected abstract boolean hasFooter();
 	
 	protected abstract void initModel(FlexiTableColumnModel columnsModel);
@@ -453,6 +456,7 @@ public abstract class GroupByController extends FormBasicController implements F
 		}
 		
 		addDataColumns(columnsModel, DATA_OFFSET);
+		addTotalDataColumn(columnsModel, TOTAL_OFFSET);
 		
 		DefaultFlexiColumnModel trendColumn = new DefaultFlexiColumnModel("heatmap.table.title.trend", columnIndex++,
 				CMD_TREND, new StaticFlexiCellRenderer("", CMD_TREND, "o_icon o_icon-lg o_icon_qual_ana_trend", null));
@@ -906,6 +910,10 @@ public abstract class GroupByController extends FormBasicController implements F
 			return rubric;
 		}
 		
+		public Slider getSlider() {
+			return slider;
+		}
+
 		public String getIdentifier() {
 			return slider.getId();
 		}
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByDataModel.java b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByDataModel.java
index 5dd5c0271ee..6ecfaed5b98 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByDataModel.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByDataModel.java
@@ -64,6 +64,9 @@ class GroupByDataModel extends DefaultFlexiTableDataModel<GroupByRow>
 				return row.getStatistic(pos);
 			}
 		}
+		if (col == GroupByController.TOTAL_OFFSET) {
+			return row.getTotal();
+		}
 		if (col < row.getGroupNamesSize()) {
 			return row.getGroupName(col);
 		}
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByRow.java b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByRow.java
index bac31b7df9e..7782a635472 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/GroupByRow.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/GroupByRow.java
@@ -35,6 +35,7 @@ public class GroupByRow {
 	private final MultiKey multiKey;
 	private final List<String> groupNames;
 	private final List<? extends GroupedStatistic> statistics;
+	private Object total;
 	
 	public GroupByRow(MultiKey multiKey, List<String> groupNames, List<? extends GroupedStatistic> statistics) {
 		this.multiKey = multiKey;
@@ -65,5 +66,17 @@ public class GroupByRow {
 	public GroupedStatistic getStatistic(int index) {
 		return statistics.get(index);
 	}
+	
+	List<? extends GroupedStatistic> getStatistics() {
+		return statistics;
+	}
+
+	public void setTotal(Object total) {
+		this.total = total;
+	}
+
+	public Object getTotal() {
+		return total;
+	}
 
 }
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/HeatMapController.java b/src/main/java/org/olat/modules/quality/analysis/ui/HeatMapController.java
index 08f1377318c..53e6247beec 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/HeatMapController.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/HeatMapController.java
@@ -20,6 +20,7 @@
 package org.olat.modules.quality.analysis.ui;
 
 import static java.util.stream.Collectors.toList;
+import static org.olat.modules.quality.analysis.ui.AnalysisUIFactory.areIdenticalRubrics;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -51,6 +52,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class HeatMapController extends GroupByController {
 	
+	private final boolean identicalRubrics;
 	private FooterGroupByDataModel dataModel;
 	private GroupedStatistics<GroupedStatistic> statistics;
 	private int maxCount;
@@ -64,7 +66,8 @@ public class HeatMapController extends GroupByController {
 			TrendDifference trendDifference, String rubricId) {
 		super(ureq, wControl, stackPanel, filterCtrl, evaluationForm, availableAttributes, multiGroupBy,
 				insufficientOnly, temporalGroupBy, trendDifference, rubricId);
-		
+		List<Rubric> rubrics = getSliders().stream().map(SliderWrapper::getRubric).distinct().collect(toList());
+		this.identicalRubrics = areIdenticalRubrics(rubrics);
 	}
 
 	@Override
@@ -109,6 +112,18 @@ public class HeatMapController extends GroupByController {
 		return columnIndex;
 	}
 	
+
+	@Override
+	protected void addTotalDataColumn(FlexiTableColumnModel columnsModel, int columnIndex) {
+		if (identicalRubrics) {
+			DefaultFlexiColumnModel columnModel = new DefaultFlexiColumnModel("", columnIndex,
+					HeatMapRenderer.variableSize(maxCount));
+			columnModel.setHeaderLabel(translate("heatmap.table.title.average"));
+			columnModel.setFooterCellRenderer(HeatMapRenderer.fixedSize());
+			columnsModel.addFlexiColumnModel(columnModel);
+		}
+	}
+	
 	@Override
 	protected List<? extends GroupedStatistic> getGroupedStatistcList(MultiKey multiKey) {
 		// Iterate over the identifiers to sort the statistics according to the headers.
@@ -142,6 +157,24 @@ public class HeatMapController extends GroupByController {
 
 	@Override
 	protected void setModelOjects(List<GroupByRow> rows) {
+		appendTotalColumn(rows);
+		List<HeatMapStatistic> footerStatistics = getFooterStatistics(rows);
+		HeatMapStatistic footerTotal = getFooterTotal(rows);
+		dataModel.setObjects(rows, footerStatistics, footerTotal);
+	}
+
+	private void appendTotalColumn(List<GroupByRow> rows) {
+		if (identicalRubrics) {
+			List<Rubric> rubrics = getSliders().stream().map(SliderWrapper::getRubric).distinct().collect(toList());
+			for (GroupByRow row : rows) {
+				List<? extends GroupedStatistic> rowStatistics = row.getStatistics();
+				HeatMapStatistic total = analysisService.calculateRubricsTotal(rowStatistics, rubrics);
+				row.setTotal(total);
+			}
+		}
+	}
+
+	private List<HeatMapStatistic> getFooterStatistics(List<GroupByRow> rows) {
 		List<HeatMapStatistic> footerStatistics = new ArrayList<>();
 		if (!rows.isEmpty()) {
 			int statisticsSize = rows.get(0).getStatisticsSize();
@@ -155,11 +188,27 @@ public class HeatMapController extends GroupByController {
 						rubric = getRubric(columnStatistic.getIdentifier());
 					}
 				}
-				HeatMapStatistic total = analysisService.calculateTotal(columnStatistics, rubric);
+				HeatMapStatistic total = analysisService.calculateSliderTotal(columnStatistics, rubric);
 				footerStatistics.add(total);
 			}
 		}
-		dataModel.setObjects(rows, footerStatistics);
+		return footerStatistics;
+	}
+
+	private HeatMapStatistic getFooterTotal(List<GroupByRow> rows) {
+		HeatMapStatistic total = null;
+		if (identicalRubrics) {
+			ArrayList<HeatMapStatistic> columnStatistics = new ArrayList<>(rows.size());
+			for (GroupByRow row : rows) {
+				Object rowTotal = row.getTotal();
+				if (rowTotal instanceof HeatMapStatistic) {
+					columnStatistics.add((HeatMapStatistic)rowTotal);
+				}
+			}
+			Rubric rubric = getSliders().stream().map(SliderWrapper::getRubric).findFirst().get();
+			total = analysisService.calculateSliderTotal(columnStatistics, rubric);
+		}
+		return total;
 	}
 
 }
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/TrendController.java b/src/main/java/org/olat/modules/quality/analysis/ui/TrendController.java
index 43060bb6250..9d9dfeedf8e 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/TrendController.java
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/TrendController.java
@@ -87,6 +87,11 @@ public class TrendController extends GroupByController {
 		}
 		return 0;
 	}
+
+	@Override
+	protected void addTotalDataColumn(FlexiTableColumnModel columnsModel, int columnIndex) {
+		//
+	}
 	
 	private List<String> getTemporalHeaders() {
 		List<TemporalKey> temporalKeys = multiTrendSeries.getTemporalKeys();
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_de.properties
index 20ca96d9a79..41dbd72f1de 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_de.properties
@@ -70,6 +70,7 @@ heatmap.legend.filters=Filter
 heatmap.legend.questions=Fragen
 heatmap.not.specified=n/a
 heatmap.table.slider.header=$org.olat.modules.forms.ui\:slider.label.code
+heatmap.table.title.average=Durchschnitt
 heatmap.table.title.blank=
 heatmap.table.title.curriculum.element=Curriculumelement
 heatmap.table.title.curriculum.organisation=Organisation des Curriculum
diff --git a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_en.properties
index a7d79d282c9..6170846e9fa 100644
--- a/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/quality/analysis/ui/_i18n/LocalStrings_en.properties
@@ -70,6 +70,7 @@ heatmap.legend.filters=Filters
 heatmap.legend.questions=Questions
 heatmap.not.specified=n/a
 heatmap.table.slider.header=$org.olat.modules.forms.ui\:slider.label.code
+heatmap.table.title.average=Average
 heatmap.table.title.blank=
 heatmap.table.title.curriculum.element=Curriculum element
 heatmap.table.title.curriculum.organisation=Organisation of curriculum
diff --git a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
index 5a9a83725e8..510f54f7aa5 100644
--- a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
+++ b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
 import static org.olat.test.JunitTestHelper.random;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -390,9 +391,49 @@ public class StatisticsCalculatorTest {
 		}
 		softly.fail("No statistic for %s, %s", multiKey, temporalKey);
 	}
+	
+	@Test
+	public void shouldCalculateRubricsTotal() {
+		when(evaluationFormManagerMock.getRubricRating(any(), any())).thenReturn(RubricRating.NEUTRAL);
+		
+		List<Slider> sliders1 = new ArrayList<>();
+		Slider slider11 = new Slider();
+		String slider11Id = random();
+		slider11.setId(slider11Id);
+		sliders1.add(slider11);
+		Slider slider12 = new Slider();
+		String slider12Id = random();
+		slider12.setId(slider12Id);
+		sliders1.add(slider12);
+		Rubric rubric1 = new Rubric();
+		rubric1.setSliders(sliders1);
+		Rubric rubric2 = new Rubric();
+		List<Slider> sliders2 = new ArrayList<>();
+		Slider slider21 = new Slider();
+		String slider21Id = random();
+		slider21.setId(slider21Id);
+		slider21.setWeight(2);
+		sliders2.add(slider21);
+		rubric2.setSliders(sliders2);
+		List<Rubric> rubrics = Arrays.asList(rubric1, rubric2);
+		
+		List<GroupedStatistic> statistics = new ArrayList<>();
+		statistics.add(new GroupedStatisticImpl(slider11Id, null, null, 1l, null, true, 1.0, null, 0));
+		statistics.add(new GroupedStatisticImpl(slider12Id, null, null, 1l, null, true, 2.0, null, 0));
+		statistics.add(new GroupedStatisticImpl(slider21Id, null, null, 2l, null, true, 3.0, null, 0));
+		
+		HeatMapStatistic total = sut.calculateRubricsTotal(statistics , rubrics);
+		
+		SoftAssertions softly = new SoftAssertions();
+		softly.assertThat(total.getCount()).isEqualTo(4);
+		softly.assertThat(total.getAvg()).isEqualTo(2.5, offset(0.001));
+		softly.assertThat(total.getRating()).isEqualTo(RubricRating.NEUTRAL);
+		softly.assertAll();
+	}
+
 
 	@Test
-	public void shouldCalculateTotal() {
+	public void shouldCalculateSliderTotal() {
 		when(evaluationFormManagerMock.getRubricRating(any(), any())).thenReturn(RubricRating.NEUTRAL);
 		
 		Rubric rubric = new Rubric();
@@ -402,7 +443,8 @@ public class StatisticsCalculatorTest {
 		statistic.add(new HeatMapStatisticImpl(3l, 5.0, null));
 		statistic.add(new HeatMapStatisticImpl(null, null, null));
 		
-		HeatMapStatistic total = sut.calculateTotal(statistic, rubric);
+		HeatMapStatistic total = sut.calculateSliderTotal(statistic, rubric);
+		
 		SoftAssertions softly = new SoftAssertions();
 		softly.assertThat(total.getCount()).isEqualTo(6);
 		softly.assertThat(total.getAvg()).isEqualTo(3.75, offset(0.001));
-- 
GitLab