From 3ad3e1883c73e3a2f541b2fd259b5b7182d89021 Mon Sep 17 00:00:00 2001
From: Colin DAMON <cdamon@ippon.fr>
Date: Wed, 26 Aug 2020 08:09:02 +0200
Subject: [PATCH] First live content

First simple versions of the activity domain
Secondary ports exists but they need their adapters
---
 borestop/README.md                            |  8 +--
 .../borestop/activity/domain/Activities.java  | 19 +++++++
 .../borestop/activity/domain/Activity.java    | 25 +++++++++
 .../borestop/activity/domain/Category.java    |  5 ++
 .../ippon/borestop/activity/domain/Idea.java  | 24 +++++++++
 .../activity/domain/IdeasRepository.java      |  5 ++
 .../borestop/activity/domain/Partner.java     | 49 ++++++++++++++++++
 .../borestop/activity/domain/Partners.java    | 40 +++++++++++++++
 .../activity/domain/PartnersRepository.java   |  5 ++
 .../secondary/RestIdeasRepository.java        | 15 ++++++
 .../activity/domain/ActivitiesUnitTest.java   | 41 +++++++++++++++
 .../activity/domain/ActivityUnitTest.java     | 51 +++++++++++++++++++
 .../activity/domain/IdeaUnitTest.java         | 30 +++++++++++
 .../activity/domain/IdeasFixture.java         | 14 +++++
 .../activity/domain/PartnerUnitTest.java      | 42 +++++++++++++++
 .../activity/domain/PartnersFixture.java      | 22 ++++++++
 .../activity/domain/PartnersUnitTest.java     | 13 +++++
 17 files changed, 405 insertions(+), 3 deletions(-)
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Activities.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Activity.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Category.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Idea.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/IdeasRepository.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Partner.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/Partners.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/domain/PartnersRepository.java
 create mode 100644 borestop/src/main/java/com/ippon/borestop/activity/infrastructure/secondary/RestIdeasRepository.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/ActivitiesUnitTest.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/ActivityUnitTest.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/IdeaUnitTest.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/IdeasFixture.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/PartnerUnitTest.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersFixture.java
 create mode 100644 borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersUnitTest.java

diff --git a/borestop/README.md b/borestop/README.md
index d30802b8..29c3fde7 100644
--- a/borestop/README.md
+++ b/borestop/README.md
@@ -2,11 +2,13 @@
 
 Création en live d'une application pour montrer l'apport de valeur pas différents niveaux de tests.
 
+## Partie 1
+
 - **Auteurs** : Hippolyte DURIX && Colin DAMON
 - **Date** : 25/08/2020
 - **Langage** : Java
-- **Niveau** : Moyen
-- **Replay** : //TODO
+- **Niveau** : Débutant
+- **Replay** : [La pyramide de tests de Kheops (partie 1) - Hippolyte et Colin](https://www.youtube.com/watch?v=rfRgJk251pw)
 
 ## JHipster
 
@@ -54,7 +56,7 @@ The service worker initialization code is commented out by default. To enable it
 ```html
 <script>
   if ('serviceWorker' in navigator) {
-    navigator.serviceWorker.register('./service-worker.js').then(function () {
+    navigator.serviceWorker.register('./service-worker.js').then(function() {
       console.log('Service Worker Registered');
     });
   }
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Activities.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Activities.java
new file mode 100644
index 00000000..eeb451b8
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Activities.java
@@ -0,0 +1,19 @@
+package com.ippon.borestop.activity.domain;
+
+public class Activities {
+  private final IdeasRepository ideas;
+  private final PartnersRepository partners;
+
+  public Activities(IdeasRepository ideas, PartnersRepository partners) {
+    this.ideas = ideas;
+    this.partners = partners;
+  }
+
+  public Activity next() {
+    Idea idea = ideas.next();
+
+    Partners matchingPartners = partners.find(idea.getCategory());
+
+    return new Activity(idea, matchingPartners);
+  }
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Activity.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Activity.java
new file mode 100644
index 00000000..5a1d4d6f
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Activity.java
@@ -0,0 +1,25 @@
+package com.ippon.borestop.activity.domain;
+
+import com.ippon.borestop.common.domain.error.Assert;
+import java.util.Collection;
+
+public class Activity {
+  private final Idea idea;
+  private final Partners partners;
+
+  public Activity(Idea idea, Partners partners) {
+    Assert.notNull("idea", idea);
+    Assert.notNull("partners", partners);
+
+    this.idea = idea;
+    this.partners = partners;
+  }
+
+  public String getLabel() {
+    return idea.getLabel();
+  }
+
+  public Collection<Partner> getPartners() {
+    return partners.getPartners();
+  }
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Category.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Category.java
new file mode 100644
index 00000000..101af047
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Category.java
@@ -0,0 +1,5 @@
+package com.ippon.borestop.activity.domain;
+
+public enum Category {
+  RELAXATION
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Idea.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Idea.java
new file mode 100644
index 00000000..3c2ba1d8
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Idea.java
@@ -0,0 +1,24 @@
+package com.ippon.borestop.activity.domain;
+
+import com.ippon.borestop.common.domain.error.Assert;
+
+public class Idea {
+  private final String label;
+  private final Category category;
+
+  public Idea(String label, Category category) {
+    Assert.notBlank("label", label);
+    Assert.notNull("category", category);
+
+    this.label = label;
+    this.category = category;
+  }
+
+  public String getLabel() {
+    return label;
+  }
+
+  public Category getCategory() {
+    return category;
+  }
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/IdeasRepository.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/IdeasRepository.java
new file mode 100644
index 00000000..4ba2365c
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/IdeasRepository.java
@@ -0,0 +1,5 @@
+package com.ippon.borestop.activity.domain;
+
+public interface IdeasRepository {
+  Idea next();
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Partner.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Partner.java
new file mode 100644
index 00000000..509fc49c
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Partner.java
@@ -0,0 +1,49 @@
+package com.ippon.borestop.activity.domain;
+
+import com.ippon.borestop.common.domain.error.Assert;
+
+public class Partner {
+  private final String name;
+  private final String website;
+
+  private Partner(PartnerBuilder builder) {
+    Assert.notBlank("name", builder.name);
+    Assert.notBlank("website", builder.website);
+
+    name = builder.name;
+    website = builder.website;
+  }
+
+  public static PartnerBuilder builder() {
+    return new PartnerBuilder();
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getWebsite() {
+    return website;
+  }
+
+  public static class PartnerBuilder {
+    private String name;
+    private String website;
+
+    public PartnerBuilder name(String name) {
+      this.name = name;
+
+      return this;
+    }
+
+    public PartnerBuilder website(String website) {
+      this.website = website;
+
+      return this;
+    }
+
+    public Partner build() {
+      return new Partner(this);
+    }
+  }
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/Partners.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/Partners.java
new file mode 100644
index 00000000..7d1a7f69
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/Partners.java
@@ -0,0 +1,40 @@
+package com.ippon.borestop.activity.domain;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class Partners {
+  private final Collection<Partner> partners;
+
+  private Partners(PartnersBuilder builder) {
+    partners = Collections.unmodifiableCollection(builder.partners);
+  }
+
+  public static Partners empty() {
+    return builder().build();
+  }
+
+  public static PartnersBuilder builder() {
+    return new PartnersBuilder();
+  }
+
+  public Collection<Partner> getPartners() {
+    return partners;
+  }
+
+  public static class PartnersBuilder {
+    private final List<Partner> partners = new ArrayList<>();
+
+    public PartnersBuilder add(Partner partner) {
+      partners.add(partner);
+
+      return this;
+    }
+
+    public Partners build() {
+      return new Partners(this);
+    }
+  }
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/domain/PartnersRepository.java b/borestop/src/main/java/com/ippon/borestop/activity/domain/PartnersRepository.java
new file mode 100644
index 00000000..987519ee
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/domain/PartnersRepository.java
@@ -0,0 +1,5 @@
+package com.ippon.borestop.activity.domain;
+
+public interface PartnersRepository {
+  Partners find(Category category);
+}
diff --git a/borestop/src/main/java/com/ippon/borestop/activity/infrastructure/secondary/RestIdeasRepository.java b/borestop/src/main/java/com/ippon/borestop/activity/infrastructure/secondary/RestIdeasRepository.java
new file mode 100644
index 00000000..ff375789
--- /dev/null
+++ b/borestop/src/main/java/com/ippon/borestop/activity/infrastructure/secondary/RestIdeasRepository.java
@@ -0,0 +1,15 @@
+package com.ippon.borestop.activity.infrastructure.secondary;
+
+import com.ippon.borestop.activity.domain.Idea;
+import com.ippon.borestop.activity.domain.IdeasRepository;
+import org.springframework.stereotype.Service;
+
+@Service
+class RestIdeasRepository implements IdeasRepository {
+
+  @Override
+  public Idea next() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivitiesUnitTest.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivitiesUnitTest.java
new file mode 100644
index 00000000..285d1c6f
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivitiesUnitTest.java
@@ -0,0 +1,41 @@
+package com.ippon.borestop.activity.domain;
+
+import static com.ippon.borestop.activity.domain.IdeasFixture.idea;
+import static com.ippon.borestop.activity.domain.IdeasFixture.label;
+import static com.ippon.borestop.activity.domain.PartnersFixture.firstPartner;
+import static com.ippon.borestop.activity.domain.PartnersFixture.secondPartner;
+import static com.ippon.borestop.activity.domain.PartnersFixture.thirdPartner;
+import static com.ippon.borestop.activity.domain.PartnersFixture.threePartners;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+class ActivitiesUnitTest {
+  @Mock
+  private IdeasRepository ideas;
+
+  @Mock
+  private PartnersRepository partners;
+
+  @InjectMocks
+  private Activities activities;
+
+  @Test
+  void shouldBuildActivity() {
+    when(ideas.next()).thenReturn(idea());
+    when(partners.find(Category.RELAXATION)).thenReturn(threePartners());
+
+    Activity activity = activities.next();
+
+    assertThat(activity.getLabel()).isEqualTo(label());
+    assertThat(activity.getPartners())
+      .usingFieldByFieldElementComparator()
+      .containsExactly(firstPartner(), secondPartner(), thirdPartner());
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivityUnitTest.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivityUnitTest.java
new file mode 100644
index 00000000..bdcdaa12
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/ActivityUnitTest.java
@@ -0,0 +1,51 @@
+package com.ippon.borestop.activity.domain;
+
+import static com.ippon.borestop.activity.domain.IdeasFixture.*;
+import static com.ippon.borestop.activity.domain.PartnersFixture.*;
+import static org.assertj.core.api.Assertions.*;
+
+import com.ippon.borestop.common.domain.error.MissingMandatoryValueException;
+import org.junit.jupiter.api.Test;
+
+class ActivityUnitTest {
+
+  @Test
+  void shouldNotBuildWithoutIdea() {
+    assertThatThrownBy(() -> new Activity(null, partners()))
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("idea");
+  }
+
+  @Test
+  void shouldNotBuildWithoutPartners() {
+    assertThatThrownBy(() -> new Activity(idea(), null))
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("partners");
+  }
+
+  @Test
+  void shouldBuildActivityWithoutMatchingPartners() {
+    Activity activity = new Activity(idea(), emptyPartners());
+
+    assertThat(activity.getLabel()).isEqualTo(label());
+    assertThat(activity.getPartners()).isEmpty();
+  }
+
+  @Test
+  void shouldBuildActivityWithThreePartnersInCategory() {
+    Activity activity = new Activity(idea(), threePartners());
+
+    assertThat(activity.getLabel()).isEqualTo(label());
+    assertThat(activity.getPartners())
+      .usingFieldByFieldElementComparator()
+      .containsExactly(firstPartner(), secondPartner(), thirdPartner());
+  }
+
+  private Partners partners() {
+    return threePartners();
+  }
+
+  private Partners emptyPartners() {
+    return Partners.empty();
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeaUnitTest.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeaUnitTest.java
new file mode 100644
index 00000000..bf94b71f
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeaUnitTest.java
@@ -0,0 +1,30 @@
+package com.ippon.borestop.activity.domain;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import com.ippon.borestop.common.domain.error.MissingMandatoryValueException;
+import org.junit.jupiter.api.Test;
+
+class IdeaUnitTest {
+
+  @Test
+  void shouldNotBuildWithoutLabel() {
+    assertThatThrownBy(() -> new Idea(null, Category.RELAXATION))
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("label");
+  }
+
+  @Test
+  void shouldNotBuildWithBlankLabel() {
+    assertThatThrownBy(() -> new Idea(" ", Category.RELAXATION))
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("label");
+  }
+
+  @Test
+  void shouldNotBuildWithoutCategory() {
+    assertThatThrownBy(() -> new Idea("label", null))
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("category");
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeasFixture.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeasFixture.java
new file mode 100644
index 00000000..f8ca164e
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/IdeasFixture.java
@@ -0,0 +1,14 @@
+package com.ippon.borestop.activity.domain;
+
+public final class IdeasFixture {
+
+  private IdeasFixture() {}
+
+  public static Idea idea() {
+    return new Idea(label(), Category.RELAXATION);
+  }
+
+  public static String label() {
+    return "This is my idea";
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnerUnitTest.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnerUnitTest.java
new file mode 100644
index 00000000..1ac1851e
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnerUnitTest.java
@@ -0,0 +1,42 @@
+package com.ippon.borestop.activity.domain;
+
+import static org.assertj.core.api.Assertions.*;
+
+import com.ippon.borestop.activity.domain.Partner.PartnerBuilder;
+import com.ippon.borestop.common.domain.error.MissingMandatoryValueException;
+import org.junit.jupiter.api.Test;
+
+class PartnerUnitTest {
+
+  @Test
+  void shouldNotBuildWithoutName() {
+    assertThatThrownBy(() -> fullBuilder().name(null).build())
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("name");
+  }
+
+  @Test
+  void shouldNotBuildWithBlankName() {
+    assertThatThrownBy(() -> fullBuilder().name(" ").build())
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("name");
+  }
+
+  @Test
+  void shouldNotBuildWithoutWebsite() {
+    assertThatThrownBy(() -> fullBuilder().website(null).build())
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("website");
+  }
+
+  @Test
+  void shouldNotBuildWithBlankWebsite() {
+    assertThatThrownBy(() -> fullBuilder().website(" ").build())
+      .isExactlyInstanceOf(MissingMandatoryValueException.class)
+      .hasMessageContaining("website");
+  }
+
+  private PartnerBuilder fullBuilder() {
+    return Partner.builder().name("name").website("http://name");
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersFixture.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersFixture.java
new file mode 100644
index 00000000..b253194c
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersFixture.java
@@ -0,0 +1,22 @@
+package com.ippon.borestop.activity.domain;
+
+public final class PartnersFixture {
+
+  private PartnersFixture() {}
+
+  public static Partners threePartners() {
+    return Partners.builder().add(firstPartner()).add(secondPartner()).add(thirdPartner()).build();
+  }
+
+  public static Partner thirdPartner() {
+    return Partner.builder().name("third").website("http://third.com").build();
+  }
+
+  public static Partner secondPartner() {
+    return Partner.builder().name("second").website("http://second.com").build();
+  }
+
+  public static Partner firstPartner() {
+    return Partner.builder().name("name").website("http://name.com").build();
+  }
+}
diff --git a/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersUnitTest.java b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersUnitTest.java
new file mode 100644
index 00000000..53a0c7d3
--- /dev/null
+++ b/borestop/src/test/java/com/ippon/borestop/activity/domain/PartnersUnitTest.java
@@ -0,0 +1,13 @@
+package com.ippon.borestop.activity.domain;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.jupiter.api.Test;
+
+class PartnersUnitTest {
+
+  @Test
+  void shouldNotBeAbleToUpdatePartners() {
+    assertThatThrownBy(() -> Partners.empty().getPartners().clear()).isExactlyInstanceOf(UnsupportedOperationException.class);
+  }
+}
-- 
GitLab