From 9b514c8414edffa7f1cba6584b07f3908fdf4f86 Mon Sep 17 00:00:00 2001
From: "Dr. Martin Goik" <goik@hdm-stuttgart.de>
Date: Sun, 14 Oct 2018 12:31:52 +0200
Subject: [PATCH] Better separation of test code + explanations

---
 .../mi/javastreams/Java8FunctionalTest.java   | 306 ++++++++++--------
 1 file changed, 163 insertions(+), 143 deletions(-)

diff --git a/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java b/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java
index 57cee719c..3b9d0a1d1 100644
--- a/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java
+++ b/P/Sda1/Streams/Solution/src/test/java/de/hdm_stuttgart/mi/javastreams/Java8FunctionalTest.java
@@ -6,6 +6,7 @@ import java.util.*;
 import java.util.stream.Collector;
 import java.util.stream.Collectors;
 
+import com.github.npathai.hamcrestopt.OptionalMatchers;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.FixMethodOrder;
@@ -25,10 +26,10 @@ public class Java8FunctionalTest {
 
     static private final List<Student> students = ImmutableList.of(
             new Student("Fred",   2, Student.Sex.MALE,   "fred@example.com")
-            ,new Student("Jane",   1, Student.Sex.FEMALE, "jane@kiv.de")
-            ,new Student("George", 4, Student.Sex.MALE,   "george@math.edu")
-            ,new Student("Bob",    2, Student.Sex.MALE,   "bob@uk.edu")
-            ,new Student("Kim",    2, Student.Sex.FEMALE, "wilde@serious.de")
+            ,new Student("Jane",  1, Student.Sex.FEMALE, "jane@kiv.de")
+            ,new Student("George",4, Student.Sex.MALE,   "george@math.edu")
+            ,new Student("Bob",   2, Student.Sex.MALE,   "bob@uk.edu")
+            ,new Student("Kim",   2, Student.Sex.FEMALE, "wilde@serious.de")
     );
 
     /**
@@ -36,11 +37,11 @@ public class Java8FunctionalTest {
      * names alphabetically ordered eliminating possible duplicates. Implementation hints:</p>
      *
      *  <pre
-     *  >"Fred",     2, Student.Sex.MALE,   "fred@example.com"
-     *   "Jane",     1, Student.Sex.FEMALE, "jane@kiv.de"
-     *   "George",   4, Student.Sex.MALE,   "george@math.edu"
-     *   "Bob", 2, Student.Sex.MALE,   "bob@uk.edu"
-     *   "Kim",      2, Student.Sex.FEMALE, "wilde@serious.de"</pre>
+     *  >{"Fred",   2, Student.Sex.MALE,   "fred@example.com"}
+     *   {"Jane",   1, Student.Sex.FEMALE, "jane@kiv.de"}
+     *   {"George", 4, Student.Sex.MALE,   "george@math.edu"}
+     *   {"Bob",    2, Student.Sex.MALE,   "bob@uk.edu"}
+     *   {"Kim",    2, Student.Sex.FEMALE, "wilde@serious.de"}</pre>
      *
      *  <p>Result: {"Bob", "Fred", "George"}</p>
      */
@@ -48,19 +49,19 @@ public class Java8FunctionalTest {
    public void allMaleDistinctNameOrderedByEmail() {
 
       final List<String> emails =
-            students.parallelStream().
-            filter(s -> s.gender == Sex.MALE).
-            sorted(Comparator.comparing(Student::getEmailAddress)).
-            map(Student::getName).
-            distinct().
-            collect(Collectors.toList());
+          students.parallelStream().
+          filter(s -> s.gender == Sex.MALE).
+          sorted(Comparator.comparing(Student::getEmailAddress)).
+          map(Student::getName).
+          distinct().
+          collect(Collectors.toList());
 
       assertThat(
-            emails,
-            Matchers.equalTo(
-                  ImmutableList.of("Bob", "Fred", "George") 
-                  ) 
-            );
+          emails,
+          Matchers.equalTo(
+             ImmutableList.of("Bob", "Fred", "George")
+          )
+      );
    }
 
     /**
@@ -80,84 +81,96 @@ public class Java8FunctionalTest {
      *     <dd>Expected value: 1 + 2 == 3</dd>
      * </dl>
      *
-     * <p>Implementation hint: Process a stream of Student instances by:</p>
+     * <p>Implementation hint: Process a stream of {@link Student} instances by:</p>
      *
      * <ol>
      *     <li>Filter students having a german email.</li>
-     *     <li>Map objects to int.</li>
+     *     <li>Map objects to mark values of type int.</li>
      *     <li>Provide a suitable
      *     <a href="https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce"
-     *     >reduce operation</a>. You may safely assume the existence of at least one Student.</li>
+     *     >reduce operation</a>. You may safely assume the existence of at least one student.</li>
      * </ol>
      *
-     * <p>You may want to read
+     * <p>You may also want to read
      *  <a href="https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce"
      *  >https://docs.oracle.com/javase/tutorial/collections/streams/reduction.html#reduce</a>.</p>
      */
    @Test
    public void markSumAllStudentsMarksHavingEmail_Dot_de() {
-      Assert.assertEquals(
-            3,                //Expected marks sum 3 == 1 + 2   
-            students.parallelStream()
-            .filter(p -> p.emailAddress.endsWith(".de")) // Jane and Kim
-            .mapToInt(Student::getMark)
-            .reduce(0, (a, b) -> a + b)
-            );
+
+       final int sumMarksOfStudentsHavingGermanEmail = students.parallelStream()
+           .filter(p -> p.emailAddress.endsWith(".de")) // Jane and Kim
+           .mapToInt(Student::getMark)
+           .reduce(0, (a, b) -> a + b);
+
+       assertThat(sumMarksOfStudentsHavingGermanEmail, Matchers.equalTo(3));
    }
 
    /**
-    * <p>A comma separated string containing all students' alphabetically ordered
-    * email addresses:</p>
+    * <p>A comma separated string containing all students' alphabetically ordered email addresses:</p>
     * 
-    * "bob@uk.edu, fred@example.com, george@math.edu, ..."
-    *  
+    * <p>{"bob@uk.edu, fred@example.com, george@math.edu, ..."}</p>
+    *
+    * <p>Implementation hint: Process a stream of {@link Student} instances by:</p>
+    *
+    * <ol>
+    *   <li>Map {@link Student} instances to their emails.</li>
+    *   <li>Sort alphabetically.</li>
+    *   <li>Use <a href="https://www.baeldung.com/java-8-collectors">a suitable</a> {@link Collector}.</li>
+    * </ol>
     */
    @Test
    public void orderedCharacterSeparatedEmailList() {
 
-      Assert.assertEquals(
-            "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de", 
-
-            students.parallelStream().
-            map(Student::getEmailAddress).
-            sorted().
-            collect(new CsvCollector(", ")) // Using ", " as separator string.
-            );
+       final String csvSortedEmails = students.stream().
+           map(Student::getEmailAddress).
+           sorted().
+           collect(Collectors.joining(", "));
 
+       assertThat(
+           csvSortedEmails,
+           Matchers.equalTo("bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de")
+       );
    }
 
    /**
     * Achieves the same result as in {@link #orderedCharacterSeparatedEmailList()}
-    * internally using a standard collector with a modified
-    * {@link Collector#finisher()} method:
-    * 
-    * "bob@uk.edu, fred@example.com, george@math.edu, ..."
-    *  
+    * internally using <a href="https://www.baeldung.com/java-8-streams#reduction">reduction</a>:
+    *
+    * <p>Implementation hint: Process a stream of {@link Student} instances by:</p>
+    *
+    * <ol>
+    *   <li>Map {@link Student} instances to their emails.</li>
+    *   <li>Sort alphabetically.</li>
+    *   <li>Implement a suitable reducing operation turning a stream of email adresses into
+    *       a single String containing comma separated email adresses.</li>
+    *   <li>You may safely assume at least one email to be present.</li>
+    * </ol>
     */
    @Test
    public void orderedCharacterSeparatedEmailList2() {
 
-      Assert.assertEquals(
-            "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de", 
+       final Optional<String> emailCsvList =
+          students.parallelStream().
+           map(Student::getEmailAddress).
+           sorted().
+           reduce((s, t) -> s + ", " + t);
 
-            students.parallelStream().
-            map(Student::getEmailAddress).
-            sorted().
-            collect
-            (Collectors.collectingAndThen
-                  (Collectors.toList(),
-                        l -> l.stream().   // A stream within a stream.
-                        reduce((s1, s2) -> s1 + ", " + s2).
-                        get()
-                        )
-                  )
-            );
+       assertThat(emailCsvList, OptionalMatchers.isPresentAndIs(
+               "bob@uk.edu, fred@example.com, george@math.edu, jane@kiv.de, wilde@serious.de"));
    }
 
    /**
-    * Get the average mark of all female students as double value.
-    * 
-    * Female marks: {1, 2}, sum == 3, average = 3. / 2 == 1.5 
+    * <p>Get the average mark of all female students as double value.</p>
+    *
+    *  <pre
+    *  >{"Jane", 1, Student.Sex.FEMALE, "jane@kiv.de"}
+    *   {"Kim",  2, Student.Sex.FEMALE, "wilde@serious.de"}</pre>
+    *
+    *
+    * <p>Female student marks sum: 1 + 2 == 3</p>
+    *
+    * <p>Result: average = 3. / 2 == 1.5</p>
     * 
     */
    @Test
@@ -169,48 +182,45 @@ public class Java8FunctionalTest {
             mapToInt(Student::getMark).
             average();
 
+      // No suitable matcher on offer
       Assert.assertTrue(femaleAverage.isPresent());
       Assert.assertEquals((1 + 2) / 2., femaleAverage.getAsDouble(), 1.E-20);
 
    }
 
    /**
-    * Group students by sex and collect their respective names:
+    * Create a {@code Map<Student.Sex, List<String>>} grouping students by sex and collecting their respective names:
     * 
-    * Female: 
-    *     "Jane"
-    *     "Kim"
-    *
-    * Male:
-    *     "Fred"
-    *     "George"
-    *     "Bob"
+    * {
+    *  Female: {"Jane", "Kim"},
+    *  Male: {"Fred", "George", "Bob"}
+    * }
     * 
     */
    @Test
    public void studentNamesBySex() {
 
       final Map<Student.Sex, List<String>> studentnamesBySex =
-            students
-            .parallelStream()
+         students.parallelStream()
             .collect(
-                  Collectors.groupingBy(
-                        Student::getSex,
-                        Collectors.mapping(
-                              Student::getName,
-                              Collectors.toList())
-                        )
-                  );
+                Collectors.groupingBy(
+                    Student::getSex,
+                Collectors.mapping(
+                    Student::getName,
+                    Collectors.toList()
+                )
+            )
+         );
 
       assertThat(
-            studentnamesBySex,
-            Matchers.<Map<Student.Sex, List<String>>> equalTo( 
-                  ImmutableMap.of (
-                        Student.Sex.MALE,   ImmutableList.of("Fred", "George", "Bob"),
-                        Student.Sex.FEMALE, ImmutableList.of("Jane", "Kim")
-                        ) 
-                  ) 
-            );
+          studentnamesBySex,
+          Matchers.equalTo(
+              ImmutableMap.of (
+                 Student.Sex.MALE,   ImmutableList.of("Fred", "George", "Bob"),
+                 Student.Sex.FEMALE, ImmutableList.of("Jane", "Kim")
+              )
+          )
+      );
    }
 
    /**
@@ -219,73 +229,83 @@ public class Java8FunctionalTest {
     * Mark 1: "Jane"               --- 1 student
     * Mark 2: "Fred", "Bob", "Kim" --- 3 students
     * Mark 4: "George"             --- 1 student
+    *
+    * Result:
+    *
+    * <pre>{
+    *  1: 1,
+    *  2: 3,
+    *  4: 1
+    * }</pre>
     * 
     */
    @Test
    public void markingFrequencies() {
       final Map<Integer, Integer> frequencyByMark =
-            students
-            .parallelStream()
-            .collect(
-                  Collectors.groupingBy(
-                        Student::getMark,
-                        Collectors.reducing(
-                              0,
-                              s -> 1,// counting heads.
-                              Integer::sum)
-                        )
-                  );
+          students
+          .parallelStream()
+          .collect(
+              Collectors.groupingBy(
+                  Student::getMark,
+                  Collectors.reducing(
+                     0,
+                      s -> 1,  // counting heads.
+                      Integer::sum
+                  )
+              )
+          );
 
-      assertThat(frequencyByMark,
-            Matchers.equalTo(
-                  ImmutableMap.of(
-                        1,   1,
-                        2,   3,
-                        4,   1
-                        ) 
-                  ) 
-            );
+      assertThat(
+          frequencyByMark,
+          Matchers.equalTo(
+             ImmutableMap.of(
+                1,   1,
+                2,   3,
+                4,   1
+              )
+          )
+      );
    }
 
    /**
-    * Students' names in ascending order grouped by by marking category:
-    * 
-    * Mark 1: {"Jane"}
-    * Mark 2: {"Bob", "Fred", "Kim"}
-    * Mark 4: {"George"} 
+    * Students' names as {@code List<String>} in ascending order grouped by by mark values:
+    * <pre>{
+    *   1: {"Jane"}
+    *   2: {"Bob", "Fred", "Kim"}
+    *   4: {"George"}
+    * }</pre>
     *
     */
    @Test
-   public void studentnamessByMark() {
+   public void studentnamesByMark() {
 
       final Map<Integer, List<String>> namesByMark =
-            students
-            .parallelStream()
-            .collect(
+          students.parallelStream().
+              collect(
                   Collectors.groupingBy(
-                        Student::getMark,
-                        Collectors.mapping(
-                              Student::getName,
-                              Collectors.collectingAndThen(
-                                    Collectors.toList(),
-                                    l -> {
-                                       Collections.sort(l);
-                                       return l;
-                                    }
-                                    )
-                              )
-                        )
-                  );
+                       Student::getMark,
+                       Collectors.mapping(
+                            Student::getName,
+                            Collectors.collectingAndThen(
+                                Collectors.toList(),
+                                l -> {
+                                    Collections.sort(l);
+                                    return l;
+                                }
+                            )
+                       )
+                  )
+              );
 
       assertThat(
-            namesByMark,
-            Matchers.<Map<Integer, List<String>>> equalTo ( 
-                  ImmutableMap.of(
-                        1,   ImmutableList.of("Jane"),
-                        2,   ImmutableList.of("Bob", "Fred", "Kim"),
-                        4,   ImmutableList.of("George")
-                        ) 
-                  ) 
-            );
+          namesByMark,
+          Matchers.equalTo (
+             ImmutableMap.of(
+                1,   ImmutableList.of("Jane"),
+                2,   ImmutableList.of("Bob", "Fred", "Kim"),
+                4,   ImmutableList.of("George")
+             )
+           )
+       );
    }
-}
+}
\ No newline at end of file
-- 
GitLab