diff --git a/README.md b/README.md index d461e54f..d20104e3 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ Here are the different challenges : - [Day 16: Make this code immutable.](exercise/day16/docs/challenge.md) - [Day 17: Design one test that has the impact of thousands.](exercise/day17/docs/challenge.md) - [Day 18: Automatically detect Linguistic Anti-Patterns (LAP).](exercise/day18/docs/challenge.md) +- [Day 19: Loosing up dead weight.](exercise/day19/docs/challenge.md) ### Solutions A solution proposal will be published here every day during the `Advent Of Craft` containing `the code` and a `step by step` guide. diff --git a/exercise/day19/docs/challenge.md b/exercise/day19/docs/challenge.md new file mode 100644 index 00000000..f91a2cd3 --- /dev/null +++ b/exercise/day19/docs/challenge.md @@ -0,0 +1,19 @@ +## Day 19: Loosing up dead weight. + +Today, you embark on the last few days of your journey. +You have been warned a big storm is brewing your way but home you go. + +You will need to leave up extra weight and tighten up the ship +for the days to come. + +The exercise of today deals with exception, again. + +You are starting to know the formula. No more exceptions. + +This time, the approach might be a bit different. + +> **Challenge of day 19: No more exception authorized - use a custom Error.** + +May your crafting journey continue! + +- 💡HINT: What object can you return to get the error state? \ No newline at end of file diff --git a/exercise/day19/docs/snippet.png b/exercise/day19/docs/snippet.png new file mode 100644 index 00000000..a98e3f44 Binary files /dev/null and b/exercise/day19/docs/snippet.png differ diff --git a/exercise/day19/pom.xml b/exercise/day19/pom.xml new file mode 100644 index 00000000..999e44a7 --- /dev/null +++ b/exercise/day19/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + + com.advent-of-craft + advent-of-craft2023 + 1.0-SNAPSHOT + + + blog-part4 + 1.0-SNAPSHOT + + 3.0.0 + 0.10.4 + + + + + org.instancio + instancio-junit + ${instancio-junit.version} + test + + + io.vavr + vavr + ${vavr.version} + + + \ No newline at end of file diff --git a/exercise/day19/src/main/java/blog/Article.java b/exercise/day19/src/main/java/blog/Article.java new file mode 100644 index 00000000..58f0c557 --- /dev/null +++ b/exercise/day19/src/main/java/blog/Article.java @@ -0,0 +1,44 @@ +package blog; + +import io.vavr.collection.Seq; + +import java.time.LocalDate; + +import static io.vavr.collection.List.of; + +public class Article { + private final String name; + private final String content; + private final Seq comments; + + public Article(String name, String content) { + this(name, content, of()); + } + + private Article(String name, String content, Seq comments) { + this.name = name; + this.content = content; + this.comments = comments; + } + + private Article addComment( + String text, + String author, + LocalDate creationDate) throws CommentAlreadyExistException { + var comment = new Comment(text, author, creationDate); + + if (comments.contains(comment)) { + throw new CommentAlreadyExistException(); + } + return new Article(name, content, comments.append(comment)); + } + + public Article addComment(String text, String author) { + return addComment(text, author, LocalDate.now()); + } + + public Seq getComments() { + return comments; + } +} + diff --git a/exercise/day19/src/main/java/blog/Comment.java b/exercise/day19/src/main/java/blog/Comment.java new file mode 100644 index 00000000..c6b25bfc --- /dev/null +++ b/exercise/day19/src/main/java/blog/Comment.java @@ -0,0 +1,6 @@ +package blog; + +import java.time.LocalDate; + +public record Comment(String text, String author, LocalDate creationDate) { +} diff --git a/exercise/day19/src/main/java/blog/CommentAlreadyExistException.java b/exercise/day19/src/main/java/blog/CommentAlreadyExistException.java new file mode 100644 index 00000000..dc8902e9 --- /dev/null +++ b/exercise/day19/src/main/java/blog/CommentAlreadyExistException.java @@ -0,0 +1,4 @@ +package blog; + +public class CommentAlreadyExistException extends RuntimeException { +} \ No newline at end of file diff --git a/exercise/day19/src/test/java/blog/ArticleBuilder.java b/exercise/day19/src/test/java/blog/ArticleBuilder.java new file mode 100644 index 00000000..51264af9 --- /dev/null +++ b/exercise/day19/src/test/java/blog/ArticleBuilder.java @@ -0,0 +1,33 @@ +package blog; + +import java.util.HashMap; + +import static org.instancio.Instancio.create; + +public class ArticleBuilder { + public static final String AUTHOR = "Pablo Escobar"; + public static final String COMMENT_TEXT = "Amazing article !!!"; + private final HashMap comments; + + public ArticleBuilder() { + comments = new HashMap<>(); + } + + public static ArticleBuilder anArticle() { + return new ArticleBuilder(); + } + + public ArticleBuilder commented() { + this.comments.put(COMMENT_TEXT, AUTHOR); + return this; + } + + public Article build() { + return comments.entrySet() + .stream() + .reduce(new Article( + create(String.class), + create(String.class) + ), (a, e) -> a.addComment(e.getKey(), e.getValue()), (p, n) -> p); + } +} diff --git a/exercise/day19/src/test/java/blog/ArticleTests.java b/exercise/day19/src/test/java/blog/ArticleTests.java new file mode 100644 index 00000000..5d7d3701 --- /dev/null +++ b/exercise/day19/src/test/java/blog/ArticleTests.java @@ -0,0 +1,74 @@ +package blog; + +import org.assertj.core.api.ThrowingConsumer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.function.Function; + +import static blog.ArticleBuilder.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.instancio.Instancio.create; + +class ArticleTests { + private Article article; + + @Test + void should_add_comment_in_an_article() { + when(article -> article.addComment(COMMENT_TEXT, AUTHOR)); + then(article -> { + assertThat(article.getComments()).hasSize(1); + assertComment(article.getComments().get(0), COMMENT_TEXT, AUTHOR); + }); + } + + @Test + void should_add_comment_in_an_article_containing_already_a_comment() { + final var newComment = create(String.class); + final var newAuthor = create(String.class); + + when(ArticleBuilder::commented, article -> article.addComment(newComment, newAuthor)); + then(article -> { + assertThat(article.getComments()).hasSize(2); + assertComment(article.getComments().last(), newComment, newAuthor); + }); + } + + private static void assertComment(Comment comment, String commentText, String author) { + assertThat(comment.text()).isEqualTo(commentText); + assertThat(comment.author()).isEqualTo(author); + } + + private void when(ArticleBuilder articleBuilder, Function act) throws CommentAlreadyExistException { + article = act.apply( + articleBuilder.build() + ); + } + + private void when(Function act) { + when(anArticle(), act); + } + + private void when(Function options, Function act) { + when(options.apply(anArticle()), act); + } + + private void then(ThrowingConsumer
act) { + act.accept(article); + } + + @Nested + class Fail { + @Test + void when__adding_an_existing_comment() { + var article = anArticle() + .commented() + .build(); + + assertThatThrownBy(() -> { + article.addComment(article.getComments().get(0).text(), article.getComments().get(0).author()); + }).isInstanceOf(CommentAlreadyExistException.class); + } + } +} \ No newline at end of file diff --git a/exercise/pom.xml b/exercise/pom.xml index db756b2a..64e14585 100644 --- a/exercise/pom.xml +++ b/exercise/pom.xml @@ -27,6 +27,7 @@ day16 day17 day18 + day19