diff --git a/pom.xml b/pom.xml
index b9da466ed..9cd6b6adb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -225,6 +225,7 @@
active-object
model-view-viewmodel
composite-entity
+ presentation
diff --git a/presentation/README.md b/presentation/README.md
new file mode 100644
index 000000000..ac0ee31f7
--- /dev/null
+++ b/presentation/README.md
@@ -0,0 +1,193 @@
+---
+layout: pattern
+title: Presentation
+folder: presentation
+permalink: /patterns/presentation/
+categories: Behavioral
+tags:
+ - Decoupling
+---
+## Also known as
+Application Model
+
+## Intent
+Presentation Model pulls the state and behavior of the view out into a model class that is part of the presentation.
+
+## Explanation
+
+Real world example
+
+> When we need to write a program with GUI, there is no need for us to put all presentation behavior in the view class. Because it will test become harder. So we can use Presentation Model Pattern to separate the behavior and view. The view only need to load the data and states from other class and show these data on the screen according to the states.
+
+In plain words
+
+> a pattern that used to divide the presentation and controlling.
+
+Code Example
+
+Class `view` is the GUI of albums. Methods `saveToPMod` and `loadFromPMod` are used to achieve synchronization.
+
+```java
+public class View {
+ /**
+ * the model that controls this view.
+ */
+ private final PresentationModel model;
+
+ private TextField txtTitle;
+ private TextField txtArtist;
+ private JCheckBox chkClassical;
+ private TextField txtComposer;
+ private JList albumList;
+ private JButton apply;
+ private JButton cancel;
+
+ public View() {
+ model = new PresentationModel(PresentationModel.albumDataSet());
+ }
+
+ /**
+ * save the data to PresentationModel.
+ */
+ public void saveToPMod() {
+ LOGGER.info("Save data to PresentationModel");
+ model.setArtist(txtArtist.getText());
+ model.setTitle(txtTitle.getText());
+ model.setIsClassical(chkClassical.isSelected());
+ model.setComposer(txtComposer.getText());
+ }
+
+ /**
+ * load the data from PresentationModel.
+ */
+ public void loadFromPMod() {
+ LOGGER.info("Load data from PresentationModel");
+ txtArtist.setText(model.getArtist());
+ txtTitle.setText(model.getTitle());
+ chkClassical.setSelected(model.getIsClassical());
+ txtComposer.setEditable(model.getIsClassical());
+ txtComposer.setText(model.getComposer());
+ }
+
+ public void createView() {
+ // the detail of GUI information like size, listenser and so on.
+ }
+}
+```
+
+Class `Album` is to store information of a album.
+
+```java
+public class Album {
+
+ private String title;
+ private String artist;
+ private boolean isClassical;
+ /**
+ * only when the album is classical,
+ * composer can have content.
+ */
+ private String composer;
+}
+
+```
+
+Class `DisplatedAlbums` is store the information of all the albums that will be displayed on GUI.
+
+```java
+public class DisplayedAlbums {
+ private final List albums;
+
+ public DisplayedAlbums() {
+ this.albums = new ArrayList<>();
+ }
+
+ public void addAlbums(final String title,
+ final String artist, final boolean isClassical,
+ final String composer) {
+ if (isClassical) {
+ this.albums.add(new Album(title, artist, true, composer));
+ } else {
+ this.albums.add(new Album(title, artist, false, ""));
+ }
+ }
+}
+```
+
+ Class `PresentationMod` is used to control all the action of GUI.
+
+```java
+public class PresentationModel {
+ private final DisplayedAlbums data;
+
+ private int selectedAlbumNumber;
+ private Album selectedAlbum;
+
+ public PresentationModel(final DisplayedAlbums dataOfAlbums) {
+ this.data = dataOfAlbums;
+ this.selectedAlbumNumber = 1;
+ this.selectedAlbum = this.data.getAlbums().get(0);
+ }
+
+ /**
+ * Changes the value of selectedAlbumNumber.
+ *
+ * @param albumNumber the number of album which is shown on the view.
+ */
+ public void setSelectedAlbumNumber(final int albumNumber) {
+ LOGGER.info("Change select number from {} to {}",
+ this.selectedAlbumNumber, albumNumber);
+ this.selectedAlbumNumber = albumNumber;
+ this.selectedAlbum = data.getAlbums().get(this.selectedAlbumNumber - 1);
+ }
+
+ public String getTitle() {
+ return selectedAlbum.getTitle();
+ }
+ // other get methods are like this, which are used to get information of selected album.
+
+ public void setTitle(final String value) {
+ LOGGER.info("Change album title from {} to {}",
+ selectedAlbum.getTitle(), value);
+ selectedAlbum.setTitle(value);
+ }
+ // other set methods are like this, which are used to get information of selected album.
+
+ /**
+ * Gets a list of albums.
+ *
+ * @return the names of all the albums.
+ */
+ public String[] getAlbumList() {
+ var result = new String[data.getAlbums().size()];
+ for (var i = 0; i < result.length; i++) {
+ result[i] = data.getAlbums().get(i).getTitle();
+ }
+ return result;
+ }
+}
+```
+
+We can run class `App` to start this demo. the checkbox is the album classical; the first text field is the name of album artist; the second is the name of album title; the last one is the name of the composer:
+
+
+
+
+## Class diagram
+
+
+## Applicability
+Use the Presentation Model Pattern when
+
+* Testing a presentation through a GUI window is often awkward, and in some cases impossible.
+* Do not determine which GUI will be used.
+
+## Related patterns
+
+- [Supervising Controller](https://martinfowler.com/eaaDev/SupervisingPresenter.html)
+- [Passive View](https://martinfowler.com/eaaDev/PassiveScreen.html)
+
+## Credits
+
+* [Presentation Model Patterns](https://martinfowler.com/eaaDev/PresentationModel.html)
+
diff --git a/presentation/etc/presentation.urm.png b/presentation/etc/presentation.urm.png
new file mode 100644
index 000000000..46690641c
Binary files /dev/null and b/presentation/etc/presentation.urm.png differ
diff --git a/presentation/etc/presentation.urm.puml b/presentation/etc/presentation.urm.puml
new file mode 100644
index 000000000..efc32901f
--- /dev/null
+++ b/presentation/etc/presentation.urm.puml
@@ -0,0 +1,59 @@
+@startuml
+package com.iluwatar.presentation {
+ class Album {
+ ~ artist : String
+ ~ composer : String
+ ~ isClassical : boolean
+ ~ rowId : int
+ ~ title : String
+ + Album(rowId : int, title : String, artist : String, isClassical : boolean, composer : String)
+ }
+ class App {
+ + App()
+ + main(args : String[]) {static}
+ }
+ class DsAlbum {
+ + albums : List
+ + albumsCache : List
+ + DsAlbum()
+ + acceptChanges()
+ + addAlbums(rowId : int, title : String, artist : String, isClassical : boolean, composer : String)
+ }
+ class PresentationMod {
+ - data : DsAlbum
+ - selectedAlbum : Album
+ - selectedAlbumNumber : int
+ + PresentationMod(data : DsAlbum)
+ + albumDataSet() : DsAlbum {static}
+ + getAlbumList() : String[]
+ + getArtist() : String
+ + getComposer() : String
+ + getIsClassical() : boolean
+ + getTitle() : String
+ + setArtist(value : String)
+ + setComposer(value : String)
+ + setIsClassical(value : boolean)
+ + setSelectedAlbumNumber(selectedAlbumNumber : int)
+ + setTitle(value : String)
+ }
+ class View {
+ ~ albumList : JList
+ ~ apply : JButton
+ ~ cancel : JButton
+ ~ chkClassical : JCheckBox
+ ~ model : PresentationMod
+ ~ notLoadView : boolean
+ ~ txtArtist : TextField
+ ~ txtComposer : TextField
+ ~ txtTitle : TextField
+ + View()
+ + createView()
+ + loadFromPMod()
+ + saveToPMod()
+ }
+}
+PresentationMod --> "-selectedAlbum" Album
+View --> "-model" PresentationMod
+DsAlbum --> "-albums" Album
+PresentationMod --> "-data" DsAlbum
+@enduml
\ No newline at end of file
diff --git a/presentation/etc/result.png b/presentation/etc/result.png
new file mode 100644
index 000000000..6b104968f
Binary files /dev/null and b/presentation/etc/result.png differ
diff --git a/presentation/pom.xml b/presentation/pom.xml
new file mode 100644
index 000000000..e5a018f27
--- /dev/null
+++ b/presentation/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.25.0-SNAPSHOT
+
+ presentation
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+
+
+
+ com.iluwatar.presentation.App
+
+
+
+
+
+
+
+
+
diff --git a/presentation/src/main/java/com/iluwatar/presentation/Album.java b/presentation/src/main/java/com/iluwatar/presentation/Album.java
new file mode 100644
index 000000000..742e49b7b
--- /dev/null
+++ b/presentation/src/main/java/com/iluwatar/presentation/Album.java
@@ -0,0 +1,31 @@
+package com.iluwatar.presentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ *A class used to store the information of album.
+ */
+@Setter
+@Getter
+@AllArgsConstructor
+public class Album {
+ /**
+ * the title of the album.
+ */
+ private String title;
+ /**
+ * the artist name of the album.
+ */
+ private String artist;
+ /**
+ * is the album classical, true or false.
+ */
+ private boolean isClassical;
+ /**
+ * only when the album is classical,
+ * composer can have content.
+ */
+ private String composer;
+}
diff --git a/presentation/src/main/java/com/iluwatar/presentation/App.java b/presentation/src/main/java/com/iluwatar/presentation/App.java
new file mode 100644
index 000000000..dc22e6bb2
--- /dev/null
+++ b/presentation/src/main/java/com/iluwatar/presentation/App.java
@@ -0,0 +1,27 @@
+package com.iluwatar.presentation;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * The Presentation model pattern is used to divide the presentation and controlling.
+ * This demo is a used to information of some albums with GUI.
+ */
+@Slf4j
+public final class App {
+ /**
+ * the constructor.
+ */
+ private App() {
+ }
+
+ /**
+ * main method.
+ *
+ * @param args args
+ */
+ public static void main(final String[] args) {
+ var view = new View();
+ view.createView();
+ }
+}
+
diff --git a/presentation/src/main/java/com/iluwatar/presentation/DisplayedAlbums.java b/presentation/src/main/java/com/iluwatar/presentation/DisplayedAlbums.java
new file mode 100644
index 000000000..6d8b23906
--- /dev/null
+++ b/presentation/src/main/java/com/iluwatar/presentation/DisplayedAlbums.java
@@ -0,0 +1,46 @@
+package com.iluwatar.presentation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * a class used to deal with albums.
+ *
+ */
+@Slf4j
+@Getter
+public class DisplayedAlbums {
+ /**
+ * albums a list of albums.
+ */
+ private final List albums;
+
+ /**
+ * a constructor method.
+ */
+ public DisplayedAlbums() {
+ this.albums = new ArrayList<>();
+ }
+
+ /**
+ * a method used to add a new album to album list.
+ *
+ * @param title the title of the album.
+ * @param artist the artist name of the album.
+ * @param isClassical is the album classical, true or false.
+ * @param composer only when the album is classical,
+ * composer can have content.
+ */
+ public void addAlbums(final String title,
+ final String artist, final boolean isClassical,
+ final String composer) {
+ if (isClassical) {
+ this.albums.add(new Album(title, artist, true, composer));
+ } else {
+ this.albums.add(new Album(title, artist, false, ""));
+ }
+ }
+}
diff --git a/presentation/src/main/java/com/iluwatar/presentation/PresentationModel.java b/presentation/src/main/java/com/iluwatar/presentation/PresentationModel.java
new file mode 100644
index 000000000..b5044cbc3
--- /dev/null
+++ b/presentation/src/main/java/com/iluwatar/presentation/PresentationModel.java
@@ -0,0 +1,163 @@
+package com.iluwatar.presentation;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * The class between view and albums, it is used to control the data.
+ */
+@Slf4j
+public class PresentationModel {
+ /**
+ * the data of all albums that will be shown.
+ */
+ private final DisplayedAlbums data;
+ /**
+ * the no of selected album.
+ */
+ private int selectedAlbumNumber;
+ /**
+ * the selected album.
+ */
+ private Album selectedAlbum;
+
+ /**
+ * Generates a set of data for testing.
+ *
+ * @return a instance of DsAlbum which store the data.
+ */
+ public static DisplayedAlbums albumDataSet() {
+ var titleList = new String[]{"HQ", "The Rough Dancer and Cyclical Night",
+ "The Black Light", "Symphony No.5"};
+ var artistList = new String[]{"Roy Harper", "Astor Piazzola",
+ "The Black Light", "CBSO"};
+ var isClassicalList = new boolean[]{false, false, false, true};
+ var composerList = new String[]{null, null, null, "Sibelius"};
+
+ var result = new DisplayedAlbums();
+ for (var i = 1; i <= titleList.length; i++) {
+ result.addAlbums(titleList[i - 1], artistList[i - 1],
+ isClassicalList[i - 1], composerList[i - 1]);
+ }
+ return result;
+ }
+
+ /**
+ * constructor method.
+ *
+ * @param dataOfAlbums the data of all the albums
+ */
+ public PresentationModel(final DisplayedAlbums dataOfAlbums) {
+ this.data = dataOfAlbums;
+ this.selectedAlbumNumber = 1;
+ this.selectedAlbum = this.data.getAlbums().get(0);
+ }
+
+ /**
+ * Changes the value of selectedAlbumNumber.
+ *
+ * @param albumNumber the number of album which is shown on the view.
+ */
+ public void setSelectedAlbumNumber(final int albumNumber) {
+ LOGGER.info("Change select number from {} to {}",
+ this.selectedAlbumNumber, albumNumber);
+ this.selectedAlbumNumber = albumNumber;
+ this.selectedAlbum = data.getAlbums().get(this.selectedAlbumNumber - 1);
+ }
+
+ /**
+ * get the title of selected album.
+ *
+ * @return the tile of selected album.
+ */
+ public String getTitle() {
+ return selectedAlbum.getTitle();
+ }
+
+ /**
+ * set the title of selected album.
+ *
+ * @param value the title which user want to user.
+ */
+ public void setTitle(final String value) {
+ LOGGER.info("Change album title from {} to {}",
+ selectedAlbum.getTitle(), value);
+ selectedAlbum.setTitle(value);
+ }
+
+ /**
+ * get the artist of selected album.
+ *
+ * @return the artist of selected album.
+ */
+ public String getArtist() {
+ return selectedAlbum.getArtist();
+ }
+
+ /**
+ * set the name of artist.
+ *
+ * @param value the name want artist to be.
+ */
+ public void setArtist(final String value) {
+ LOGGER.info("Change album artist from {} to {}",
+ selectedAlbum.getArtist(), value);
+ selectedAlbum.setArtist(value);
+ }
+
+ /**
+ * Gets a boolean value which represents whether the album is classical.
+ *
+ * @return is the album classical.
+ */
+ public boolean getIsClassical() {
+ return selectedAlbum.isClassical();
+ }
+
+ /**
+ * set the isClassical of album.
+ *
+ * @param value is the album classical.
+ */
+ public void setIsClassical(final boolean value) {
+ LOGGER.info("Change album isClassical from {} to {}",
+ selectedAlbum.isClassical(), value);
+ selectedAlbum.setClassical(value);
+ }
+
+ /**
+ * get is classical of the selected album.
+ *
+ * @return is the album classical.
+ */
+ public String getComposer() {
+ return selectedAlbum.isClassical() ? selectedAlbum.getComposer() : "";
+ }
+
+ /**
+ * Sets the name of composer when the album is classical.
+ *
+ * @param value the name of composer.
+ */
+ public void setComposer(final String value) {
+ if (selectedAlbum.isClassical()) {
+ LOGGER.info("Change album composer from {} to {}",
+ selectedAlbum.getComposer(), value);
+ selectedAlbum.setComposer(value);
+ } else {
+ LOGGER.info("Composer can not be changed");
+ }
+ }
+
+ /**
+ * Gets a list of albums.
+ *
+ * @return the names of all the albums.
+ */
+ public String[] getAlbumList() {
+ var result = new String[data.getAlbums().size()];
+ for (var i = 0; i < result.length; i++) {
+ result[i] = data.getAlbums().get(i).getTitle();
+ }
+ return result;
+ }
+}
diff --git a/presentation/src/main/java/com/iluwatar/presentation/View.java b/presentation/src/main/java/com/iluwatar/presentation/View.java
new file mode 100644
index 000000000..92a1c62f4
--- /dev/null
+++ b/presentation/src/main/java/com/iluwatar/presentation/View.java
@@ -0,0 +1,167 @@
+package com.iluwatar.presentation;
+
+import java.awt.TextField;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JList;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Generates the GUI of albums.
+ */
+@Getter
+@Slf4j
+public class View {
+ /**
+ * the model that controls this view.
+ */
+ private final PresentationModel model;
+
+ /**
+ * the filed to show and modify title.
+ */
+ private TextField txtTitle;
+ /**
+ * the filed to show and modify the name of artist.
+ */
+ private TextField txtArtist;
+ /**
+ * the checkbox for is classical.
+ */
+ private JCheckBox chkClassical;
+ /**
+ * the filed to show and modify composer.
+ */
+ private TextField txtComposer;
+ /**
+ * a list to show all the name of album.
+ */
+ private JList albumList;
+ /**
+ * a button to apply of all the change.
+ */
+ private JButton apply;
+ /**
+ * roll back the change.
+ */
+ private JButton cancel;
+
+ /**
+ * the value of the text field size.
+ */
+ static final int WIDTH_TXT = 200;
+ static final int HEIGHT_TXT = 50;
+
+ /**
+ * the value of the GUI size and location.
+ */
+ static final int LOCATION_X = 200;
+ static final int LOCATION_Y = 200;
+ static final int WIDTH = 500;
+ static final int HEIGHT = 300;
+
+ /**
+ * constructor method.
+ */
+ public View() {
+ model = new PresentationModel(PresentationModel.albumDataSet());
+ }
+
+ /**
+ * save the data to PresentationModel.
+ */
+ public void saveToPMod() {
+ LOGGER.info("Save data to PresentationModel");
+ model.setArtist(txtArtist.getText());
+ model.setTitle(txtTitle.getText());
+ model.setIsClassical(chkClassical.isSelected());
+ model.setComposer(txtComposer.getText());
+ }
+
+ /**
+ * load the data from PresentationModel.
+ */
+ public void loadFromPMod() {
+ LOGGER.info("Load data from PresentationModel");
+ txtArtist.setText(model.getArtist());
+ txtTitle.setText(model.getTitle());
+ chkClassical.setSelected(model.getIsClassical());
+ txtComposer.setEditable(model.getIsClassical());
+ txtComposer.setText(model.getComposer());
+ }
+
+ /**
+ * initialize the GUI.
+ */
+ public void createView() {
+ var frame = new JFrame("Album");
+ var b1 = Box.createHorizontalBox();
+
+ frame.add(b1);
+ albumList = new JList<>(model.getAlbumList());
+ albumList.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ model.setSelectedAlbumNumber(albumList.getSelectedIndex() + 1);
+ loadFromPMod();
+ }
+ });
+ b1.add(albumList);
+
+ var b2 = Box.createVerticalBox();
+ b1.add(b2);
+
+ txtArtist = new TextField();
+ txtTitle = new TextField();
+
+ txtArtist.setSize(WIDTH_TXT, HEIGHT_TXT);
+ txtTitle.setSize(WIDTH_TXT, HEIGHT_TXT);
+
+ chkClassical = new JCheckBox();
+ txtComposer = new TextField();
+ chkClassical.addActionListener(itemEvent -> {
+ txtComposer.setEditable(chkClassical.isSelected());
+ if (!chkClassical.isSelected()) {
+ txtComposer.setText("");
+ }
+ });
+ txtComposer.setSize(WIDTH_TXT, HEIGHT_TXT);
+ txtComposer.setEditable(model.getIsClassical());
+
+ apply = new JButton("Apply");
+ apply.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ saveToPMod();
+ loadFromPMod();
+ }
+ });
+ cancel = new JButton("Cancel");
+ cancel.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseClicked(final MouseEvent e) {
+ loadFromPMod();
+ }
+ });
+
+ b2.add(txtArtist);
+ b2.add(txtTitle);
+
+ b2.add(chkClassical);
+ b2.add(txtComposer);
+
+ b2.add(apply);
+ b2.add(cancel);
+
+ frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+ frame.setBounds(LOCATION_X, LOCATION_Y, WIDTH, HEIGHT);
+ frame.setVisible(true);
+ }
+
+}
diff --git a/presentation/src/test/java/com/iluwatar/presentation/AlbumTest.java b/presentation/src/test/java/com/iluwatar/presentation/AlbumTest.java
new file mode 100644
index 000000000..251a45bd4
--- /dev/null
+++ b/presentation/src/test/java/com/iluwatar/presentation/AlbumTest.java
@@ -0,0 +1,37 @@
+package com.iluwatar.presentation;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AlbumTest {
+ @Test
+ void testSetTitle(){
+ Album album = new Album("a", "b", false, "");
+ album.setTitle("b");
+ assertEquals("b", album.getTitle());
+ }
+
+ @Test
+ void testSetArtist(){
+ Album album = new Album("a", "b", false, "");
+ album.setArtist("c");
+ assertEquals("c", album.getArtist());
+ }
+
+ @Test
+ void testSetClassical(){
+ Album album = new Album("a", "b", false, "");
+ album.setClassical(true);
+ assertTrue(album.isClassical());
+ }
+
+ @Test
+ void testSetComposer(){
+ Album album = new Album("a", "b", false, "");
+ album.setClassical(true);
+ album.setComposer("w");
+ assertEquals("w", album.getComposer());
+ }
+}
diff --git a/presentation/src/test/java/com/iluwatar/presentation/AppTest.java b/presentation/src/test/java/com/iluwatar/presentation/AppTest.java
new file mode 100644
index 000000000..b29c0f3a3
--- /dev/null
+++ b/presentation/src/test/java/com/iluwatar/presentation/AppTest.java
@@ -0,0 +1,42 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.presentation;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+/**
+ * Issue: Add at least one assertion to this test case.
+ *
+ * Solution: Inserted assertion to check whether the execution of the main method in {@link App}
+ * throws an exception.
+ */
+class AppTest {
+
+ @Test
+ void shouldExecuteApplicationWithoutException() {
+ assertDoesNotThrow(() -> App.main(new String[]{}));
+ }
+}
diff --git a/presentation/src/test/java/com/iluwatar/presentation/DisplayedAlbumsTest.java b/presentation/src/test/java/com/iluwatar/presentation/DisplayedAlbumsTest.java
new file mode 100644
index 000000000..7b850c01d
--- /dev/null
+++ b/presentation/src/test/java/com/iluwatar/presentation/DisplayedAlbumsTest.java
@@ -0,0 +1,22 @@
+package com.iluwatar.presentation;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DisplayedAlbumsTest {
+ @Test
+ void testAdd_true(){
+ DisplayedAlbums displayedAlbums = new DisplayedAlbums();
+ displayedAlbums.addAlbums("title", "artist", true, "composer");
+ assertEquals("composer", displayedAlbums.getAlbums().get(0).getComposer());
+
+ }
+
+ @Test
+ void testAdd_false(){
+ DisplayedAlbums displayedAlbums = new DisplayedAlbums();
+ displayedAlbums.addAlbums("title", "artist", false, "composer");
+ assertEquals("", displayedAlbums.getAlbums().get(0).getComposer());
+ }
+}
diff --git a/presentation/src/test/java/com/iluwatar/presentation/PresentationTest.java b/presentation/src/test/java/com/iluwatar/presentation/PresentationTest.java
new file mode 100644
index 000000000..52a5e31ed
--- /dev/null
+++ b/presentation/src/test/java/com/iluwatar/presentation/PresentationTest.java
@@ -0,0 +1,117 @@
+/*
+ * The MIT License
+ * Copyright © 2014-2021 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.iluwatar.presentation;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PresentationTest {
+ String[] albumList = {"HQ", "The Rough Dancer and Cyclical Night", "The Black Light", "Symphony No.5"};
+
+ @Test
+ void testCreateAlbumList() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String[] list = model.getAlbumList();
+ assertEquals(Arrays.toString(albumList), Arrays.toString(list));
+ }
+
+ @Test
+ void testSetSelectedAlbumNumber_1() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ final int selectId = 2;
+ model.setSelectedAlbumNumber(selectId);
+ assertEquals(albumList[selectId - 1], model.getTitle());
+ }
+
+ @Test
+ void testSetSelectedAlbumNumber_2() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ final int selectId = 4;
+ model.setSelectedAlbumNumber(selectId);
+ assertEquals(albumList[selectId - 1], model.getTitle());
+ }
+
+ @Test
+ void testSetTitle_1() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testTitle = "TestTile";
+ model.setTitle(testTitle);
+ assertEquals(testTitle, model.getTitle());
+ }
+
+ @Test
+ void testSetTitle_2() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testTitle = "";
+ model.setTitle(testTitle);
+ assertEquals(testTitle, model.getTitle());
+ }
+
+ @Test
+ void testSetArtist_1() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testArtist = "TestArtist";
+ model.setArtist(testArtist);
+ assertEquals(testArtist, model.getArtist());
+ }
+
+ @Test
+ void testSetArtist_2() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testArtist = "";
+ model.setArtist(testArtist);
+ assertEquals(testArtist, model.getArtist());
+ }
+
+ @Test
+ void testSetIsClassical() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ model.setIsClassical(true);
+ assertTrue(model.getIsClassical());
+ }
+
+ @Test
+ void testSetComposer_false() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testComposer = "TestComposer";
+
+ model.setIsClassical(false);
+ model.setComposer(testComposer);
+ assertEquals("", model.getComposer());
+ }
+
+ @Test
+ void testSetComposer_true() {
+ PresentationModel model = new PresentationModel(PresentationModel.albumDataSet());
+ String testComposer = "TestComposer";
+
+ model.setIsClassical(true);
+ model.setComposer(testComposer);
+ assertEquals(testComposer, model.getComposer());
+ }
+}
diff --git a/presentation/src/test/java/com/iluwatar/presentation/ViewTest.java b/presentation/src/test/java/com/iluwatar/presentation/ViewTest.java
new file mode 100644
index 000000000..c50a6b796
--- /dev/null
+++ b/presentation/src/test/java/com/iluwatar/presentation/ViewTest.java
@@ -0,0 +1,55 @@
+package com.iluwatar.presentation;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ViewTest {
+ String[] albumList = {"HQ", "The Rough Dancer and Cyclical Night", "The Black Light", "Symphony No.5"};
+
+ @Test
+ void testSave_setArtistAndTitle(){
+ View view = new View();
+ view.createView();
+ String testTitle = "testTitle";
+ String testArtist = "testArtist";
+ view.getTxtArtist().setText(testArtist);
+ view.getTxtTitle().setText(testTitle);
+ view.saveToPMod();
+ view.loadFromPMod();
+ assertEquals(testTitle, view.getModel().getTitle());
+ assertEquals(testArtist, view.getModel().getArtist());
+ }
+
+ @Test
+ void testSave_setClassicalAndComposer(){
+ View view = new View();
+ view.createView();
+ boolean isClassical = true;
+ String testComposer = "testComposer";
+ view.getChkClassical().setSelected(isClassical);
+ view.getTxtComposer().setText(testComposer);
+ view.saveToPMod();
+ view.loadFromPMod();
+ assertTrue(view.getModel().getIsClassical());
+ assertEquals(testComposer, view.getModel().getComposer());
+ }
+
+ @Test
+ void testLoad_1(){
+ View view = new View();
+ view.createView();
+ view.getModel().setSelectedAlbumNumber(2);
+ view.loadFromPMod();
+ assertEquals(albumList[1], view.getModel().getTitle());
+ }
+
+ @Test
+ void testLoad_2(){
+ View view = new View();
+ view.createView();
+ view.getModel().setSelectedAlbumNumber(4);
+ view.loadFromPMod();
+ assertEquals(albumList[3], view.getModel().getTitle());
+ }
+}