From 04140bc27d63c648f785feeb5b2aa8606bd20b7f Mon Sep 17 00:00:00 2001
From: uhensler <urs.hensler@frentix.com>
Date: Tue, 28 Jan 2020 11:39:41 +0100
Subject: [PATCH] OO-4207: A course with only optional elements is always 100%
 completed

---
 .../scoring/AverageCompletionEvaluator.java   |  5 ++
 .../AverageCompletionEvaluatorTest.java       | 56 +++++++++++++++----
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/olat/course/run/scoring/AverageCompletionEvaluator.java b/src/main/java/org/olat/course/run/scoring/AverageCompletionEvaluator.java
index 39a98367543..62731b6633b 100644
--- a/src/main/java/org/olat/course/run/scoring/AverageCompletionEvaluator.java
+++ b/src/main/java/org/olat/course/run/scoring/AverageCompletionEvaluator.java
@@ -68,9 +68,11 @@ public class AverageCompletionEvaluator implements CompletionEvaluator {
 		
 		int count = 0;
 		double completion = 0.0;
+		boolean allOptional = true;
 		for (CourseNode child: visitor.getCourseNodes()) {
 			AssessmentEvaluation assessmentEvaluation = scoreAccounting.evalCourseNode(child);
 			if (isMandatory(assessmentEvaluation)) {
+				allOptional = false;
 				AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(child);
 				int nodeCount = 0;
 				double nodeCompletion = 0.0;
@@ -92,6 +94,9 @@ public class AverageCompletionEvaluator implements CompletionEvaluator {
 			}
 		}
 		
+		if (allOptional) {
+			return 1.0;
+		}
 		return count > 0? completion / count: null;
 	}
 
diff --git a/src/test/java/org/olat/course/run/scoring/AverageCompletionEvaluatorTest.java b/src/test/java/org/olat/course/run/scoring/AverageCompletionEvaluatorTest.java
index 04ba9394419..2e6fdce9def 100644
--- a/src/test/java/org/olat/course/run/scoring/AverageCompletionEvaluatorTest.java
+++ b/src/test/java/org/olat/course/run/scoring/AverageCompletionEvaluatorTest.java
@@ -72,16 +72,6 @@ public class AverageCompletionEvaluatorTest {
 
 		sut = new AverageCompletionEvaluator(courseAssessmentService, UNWEIGHTED);
 	}
-	
-	@Test
-	public void shouldReturnNullIfItHasNoChildren() {
-		MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
-		CourseNode parent = new STCourseNode();
-		
-		Double completion = sut.getCompletion(null, parent, scoreAccounting);
-		
-		assertThat(completion).isNull();
-	}
 
 	@Test
 	public void shouldGetAverageCompletionOfChildren() {
@@ -267,6 +257,52 @@ public class AverageCompletionEvaluatorTest {
 		double expected = (1.0 + 0.0 + 1.0 + 0.5 ) / 4;
 		assertThat(completion).isEqualTo(expected, offset(0.001));
 	}
+	
+	@Test
+	public void shouldReturnFullCompletionIfItHasNoChildren() {
+		MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
+		CourseNode parent = new STCourseNode();
+		
+		Double completion = sut.getCompletion(null, parent, scoreAccounting);
+		
+		assertThat(completion).isEqualTo(1.0);
+	}
+
+	@Test
+	public void shouldReturnFullCompletionIfAllChildrenAreOptional() {
+		MappedScoreAccounting scoreAccounting = new MappedScoreAccounting();
+		
+		// Parent: calculated
+		CourseNode parent = new STCourseNode();
+		// Child without own completion: fully assessed
+		CourseNode child1 = new Card2BrainCourseNode();
+		parent.addChild(child1);
+		AssessmentEvaluation assessedEvaluation1 = createAssessmentEvaluation(optional, null, null, null, Boolean.TRUE);
+		scoreAccounting.put(child1, assessedEvaluation1);
+		when(courseAssessmentService.getAssessmentConfig(child1)).thenReturn(configNone);
+		// Child without own completion: not ready
+		CourseNode child2 = new Card2BrainCourseNode();
+		parent.addChild(child2);
+		AssessmentEvaluation assessedEvaluation2 = createAssessmentEvaluation(optional, null, null, AssessmentEntryStatus.notReady, Boolean.FALSE);
+		scoreAccounting.put(child2, assessedEvaluation2);
+		when(courseAssessmentService.getAssessmentConfig(child2)).thenReturn(configNone);
+		// Child with own completion: completion 0.5, fully assessed
+		CourseNode child3 = new Card2BrainCourseNode();
+		parent.addChild(child3);
+		AssessmentEvaluation childEvaluation3 = createAssessmentEvaluation(optional, null, Double.valueOf(0.5), null, Boolean.TRUE);
+		scoreAccounting.put(child3, childEvaluation3);
+		when(courseAssessmentService.getAssessmentConfig(child3)).thenReturn(configSetByNode);
+		// Child with own completion: completion 0.5, not fully assessed
+		CourseNode child4 = new Card2BrainCourseNode();
+		parent.addChild(child4);
+		AssessmentEvaluation childEvaluation4 = createAssessmentEvaluation(optional, null, Double.valueOf(0.5), null, null);
+		scoreAccounting.put(child4, childEvaluation4);
+		when(courseAssessmentService.getAssessmentConfig(child4)).thenReturn(configSetByNode);
+		
+		Double completion = sut.getCompletion(null, parent, scoreAccounting);
+		
+		assertThat(completion).isEqualTo(1.0);
+	}
 
 	
 	private AssessmentEvaluation createAssessmentEvaluation(AssessmentObligation obligation, Integer duration,
-- 
GitLab