diff --git a/.github/badges/branches.svg b/.github/badges/branches.svg new file mode 100644 index 0000000..af316de --- /dev/null +++ b/.github/badges/branches.svg @@ -0,0 +1 @@ +branches85.7% \ No newline at end of file diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg new file mode 100644 index 0000000..737c552 --- /dev/null +++ b/.github/badges/jacoco.svg @@ -0,0 +1 @@ +coverage94.9% \ No newline at end of file diff --git a/.github/workflows/merged_master.yml b/.github/workflows/merged_master.yml new file mode 100644 index 0000000..e3faa84 --- /dev/null +++ b/.github/workflows/merged_master.yml @@ -0,0 +1,47 @@ +name: maven build + +on: + pull_request: + types: [closed] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'zulu' + cache: maven + - name: Build with Maven + run: mvn -B package --file pom.xml + + - name: Generate JaCoCo Badge + uses: cicirello/jacoco-badge-generator@v2 + with: + generate-branches-badge: true + + - name: Log coverage percentage + run: | + echo "coverage = ${{ steps.jacoco.outputs.coverage }}" + echo "branch coverage = ${{ steps.jacoco.outputs.branches }}" + + - name: Commit the badge (if it changed) + run: | + if [[ `git status --porcelain` ]]; then + git config --global user.name 'Luis' + git config --global user.email 'lpenap@users.noreply.github.com' + git add -A + git commit -m "Autogenerated JaCoCo coverage badge" + git push + fi + + - name: Upload JaCoCo coverage report + uses: actions/upload-artifact@v4 + with: + name: jacoco-report + path: target/site/jacoco/ diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..50500a1 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,18 @@ +name: PR Build + +on: + pull_request: + branches: ['**'] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '21' + - name: Build and Test + run: ./mvnw -B verify diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index 4b3a893..3fcdf84 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -33,7 +33,7 @@ public class MavenWrapperDownloader { * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"; /** * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index cd0d451..3c11064 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1 +1 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8837af0..0000000 --- a/.travis.yml +++ /dev/null @@ -1,6 +0,0 @@ -dist: bionic -services: - - xvfb -language: java -jdk: - - openjdk11 diff --git a/README.md b/README.md index 1930a36..d046e0c 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ -[![codebeat badge](https://codebeat.co/badges/4c328c5d-1722-459f-aaa1-437a0ed6201f)](https://codebeat.co/projects/github-com-lpenap-java-patterns-and-constructs-master) -[![Build Status](https://travis-ci.org/lpenap/java-patterns-and-constructs.svg)](https://travis-ci.org/lpenap/java-patterns-and-constructs) +[![maven build](https://github.com/lpenap/java-patterns-and-constructs/actions/workflows/merged_master.yml/badge.svg)](https://github.com/lpenap/java-patterns-and-constructs/actions/workflows/merged_master.yml) [![GitHub release](https://img.shields.io/github/release/lpenap/java-patterns-and-constructs)](//github.com/lpenap/java-patterns-and-constructs/releases/latest) +[![codebeat badge](https://codebeat.co/badges/4c328c5d-1722-459f-aaa1-437a0ed6201f)](https://codebeat.co/projects/github-com-lpenap-java-patterns-and-constructs-master) +![Coverage](.github/badges/jacoco.svg) # Java Design Patterns and Constructs Collection of patterns and other constructs in Java for educational purposes. (See *Contributing* section if you would like to contribute). ## Quickstart -* Install a Java 11 implementation (like openjdk11) +* Install a Java 21 implementation (like openjdk21) * Clone and run the spring-boot maven goal: ```bash git clone https://github.com/lpenap/java-patterns-and-constructs @@ -15,9 +16,15 @@ cd java-patterns-and-constructs ``` ## Da List ### Patterns +* [Abstract Factory](src/main/java/com/penapereira/example/constructs/abstractfactory/) +* [Adapter](src/main/java/com/penapereira/example/constructs/adapter/) +* [Decorator](src/main/java/com/penapereira/example/constructs/decorator/) +* [Factory](src/main/java/com/penapereira/example/constructs/factory/) * [Factory Method](src/main/java/com/penapereira/example/constructs/factorymethod/) * [Observer](src/main/java/com/penapereira/example/constructs/observer/) * [Singleton](src/main/java/com/penapereira/example/constructs/singleton/) +* [Strategy](src/main/java/com/penapereira/example/constructs/strategy/) +* [Template Method](src/main/java/com/penapereira/example/constructs/templatemethod/) ### Constructs and Problems * [Producer/Consumer](src/main/java/com/penapereira/example/constructs/producerconsumer/), a multi-process synchronization problem. diff --git a/pom.xml b/pom.xml index 36c0194..ae836ae 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.7.RELEASE - - + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + com.penapereira java-patterns-and-constructs 0.0.2 @@ -15,8 +15,8 @@ Collection of patterns and other constructs in Java - 11 - + 21 + @@ -47,13 +47,67 @@ - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + + prepare-agent + + + + generate-code-coverage-report + test + + report + check + + + + + BUNDLE + + + INSTRUCTION + COVEREDRATIO + 0.90 + + + + + + **/*ExampleRunner* + **/AppCommandLineRunner* + **/ExamplesCommandLineRunner* + **/ProducerConsumerExampleRunner* + **/Consumer* + **/JavaPatternsAndConstructsApplication* + **/MainWindow* + **/Messages* + **/ApplicationProperties* + **/HyperlinkMouseListener* + **/ObservableAbstract* + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactory.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactory.java new file mode 100644 index 0000000..dc3c24c --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactory.java @@ -0,0 +1,6 @@ +package com.penapereira.example.constructs.abstractfactory; + +public interface AbstractFactory { + ProductA createProductA(); + ProductB createProductB(); +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunner.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunner.java new file mode 100644 index 0000000..74c3dfb --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunner.java @@ -0,0 +1,28 @@ +package com.penapereira.example.constructs.abstractfactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.penapereira.example.constructs.app.ExampleRunnerInterface; + +@Component +public class AbstractFactoryExampleRunner implements ExampleRunnerInterface { + + private static final Logger log = + LoggerFactory.getLogger(AbstractFactoryExampleRunner.class); + + @Override + public void runExample() throws Exception { + log.trace("Executing Abstract Factory Pattern Implementation:"); + + AbstractFactory factory1 = new Factory1(); + AbstractFactory factory2 = new Factory2(); + + log.trace(" " + factory1.createProductA().name()); + log.trace(" " + factory1.createProductB().name()); + + log.trace(" " + factory2.createProductA().name()); + log.trace(" " + factory2.createProductB().name()); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory1.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory1.java new file mode 100644 index 0000000..a6adccf --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory1.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class Factory1 implements AbstractFactory { + + @Override + public ProductA createProductA() { + return new ProductA1(); + } + + @Override + public ProductB createProductB() { + return new ProductB1(); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory2.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory2.java new file mode 100644 index 0000000..997ce00 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/Factory2.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class Factory2 implements AbstractFactory { + + @Override + public ProductA createProductA() { + return new ProductA2(); + } + + @Override + public ProductB createProductB() { + return new ProductB2(); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA.java new file mode 100644 index 0000000..6d60d29 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA.java @@ -0,0 +1,5 @@ +package com.penapereira.example.constructs.abstractfactory; + +public interface ProductA { + String name(); +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA1.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA1.java new file mode 100644 index 0000000..0f31eec --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA1.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class ProductA1 implements ProductA { + + @Override + public String name() { + return "ProductA1"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA2.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA2.java new file mode 100644 index 0000000..7f6e76e --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductA2.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class ProductA2 implements ProductA { + + @Override + public String name() { + return "ProductA2"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB.java new file mode 100644 index 0000000..90c8f55 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB.java @@ -0,0 +1,5 @@ +package com.penapereira.example.constructs.abstractfactory; + +public interface ProductB { + String name(); +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB1.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB1.java new file mode 100644 index 0000000..95afab8 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB1.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class ProductB1 implements ProductB { + + @Override + public String name() { + return "ProductB1"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB2.java b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB2.java new file mode 100644 index 0000000..c804cbc --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/abstractfactory/ProductB2.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.abstractfactory; + +public class ProductB2 implements ProductB { + + @Override + public String name() { + return "ProductB2"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/adapter/Adaptee.java b/src/main/java/com/penapereira/example/constructs/adapter/Adaptee.java new file mode 100644 index 0000000..93a76be --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/adapter/Adaptee.java @@ -0,0 +1,7 @@ +package com.penapereira.example.constructs.adapter; + +public class Adaptee { + public String specificRequest() { + return "Adaptee"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/adapter/Adapter.java b/src/main/java/com/penapereira/example/constructs/adapter/Adapter.java new file mode 100644 index 0000000..fd50fa2 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/adapter/Adapter.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.adapter; + +public class Adapter implements Target { + private final Adaptee adaptee; + + public Adapter(Adaptee adaptee) { + this.adaptee = adaptee; + } + + @Override + public String request() { + return "Adapter(" + adaptee.specificRequest() + ")"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/adapter/AdapterExampleRunner.java b/src/main/java/com/penapereira/example/constructs/adapter/AdapterExampleRunner.java new file mode 100644 index 0000000..5ab0436 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/adapter/AdapterExampleRunner.java @@ -0,0 +1,23 @@ +package com.penapereira.example.constructs.adapter; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.penapereira.example.constructs.app.ExampleRunnerInterface; + +@Component +public class AdapterExampleRunner implements ExampleRunnerInterface { + + private static final Logger log = LoggerFactory.getLogger(AdapterExampleRunner.class); + + @Override + public void runExample() throws Exception { + log.trace("Executing Adapter Pattern Implementation"); + + Adaptee adaptee = new Adaptee(); + Target target = new Adapter(adaptee); + + log.trace(" " + target.request()); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/adapter/Target.java b/src/main/java/com/penapereira/example/constructs/adapter/Target.java new file mode 100644 index 0000000..8943acd --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/adapter/Target.java @@ -0,0 +1,5 @@ +package com.penapereira.example.constructs.adapter; + +public interface Target { + String request(); +} diff --git a/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java b/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java index cc94359..3c46b0a 100644 --- a/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java +++ b/src/main/java/com/penapereira/example/constructs/app/properties/Messages.java @@ -16,6 +16,7 @@ public class Messages { protected String info; protected String examplesFound; protected String enableTraceToSeeExamplesDetails; - protected String enableDebugToSeeExamplesList; - protected String separator; + protected String enableDebugToSeeExamplesList; + protected String separator; + protected String outputTitle; } diff --git a/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java b/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java new file mode 100644 index 0000000..1056fe7 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/app/ui/GuiAppender.java @@ -0,0 +1,30 @@ +package com.penapereira.example.constructs.app.ui; + +import java.awt.EventQueue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.AppenderBase; + +@Component +public class GuiAppender extends AppenderBase implements InitializingBean { + + @Autowired + private MainWindow mainWindow; + + @Override + public void afterPropertiesSet() throws Exception { + ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).addAppender(this); + start(); + } + + @Override + protected void append(ILoggingEvent eventObject) { + EventQueue.invokeLater(() -> mainWindow.appendOutput(eventObject.getFormattedMessage() + System.lineSeparator())); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java b/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java index dbbe964..a112fd3 100644 --- a/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java +++ b/src/main/java/com/penapereira/example/constructs/app/ui/MainWindow.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.awt.Cursor; import java.awt.Font; +import java.awt.BorderLayout; import java.awt.GridLayout; import java.io.IOException; @@ -10,7 +11,9 @@ import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; +import javax.swing.JScrollPane; import javax.swing.JSeparator; +import javax.swing.JTextArea; import javax.swing.SwingConstants; import org.slf4j.Logger; @@ -26,7 +29,9 @@ public class MainWindow extends JFrame { private static final Logger log = LoggerFactory.getLogger(MainWindow.class); - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + + private JTextArea outputArea; @Autowired Messages msg; @@ -65,13 +70,23 @@ private void loadIcon() { } } - private JPanel getMainComponent() { - JPanel mainPanel = new JPanel(new GridLayout(4, 1)); - createCenteredTitle(msg.getGreeting(), mainPanel); - createCenteredLabelOnPanel(msg.getInfo(), mainPanel); - createCenteredHyperlink(msg.getHomeUrl(), mainPanel); - return mainPanel; - } + private JPanel getMainComponent() { + JPanel mainPanel = new JPanel(new BorderLayout()); + + JPanel infoPanel = new JPanel(new GridLayout(4, 1)); + createCenteredTitle(msg.getGreeting(), infoPanel); + createCenteredLabelOnPanel(msg.getInfo(), infoPanel); + createCenteredHyperlink(msg.getHomeUrl(), infoPanel); + mainPanel.add(infoPanel, BorderLayout.NORTH); + + outputArea = new JTextArea(10, 40); + outputArea.setEditable(false); + JScrollPane scrollPane = new JScrollPane(outputArea); + scrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder(msg.getOutputTitle())); + mainPanel.add(scrollPane, BorderLayout.CENTER); + + return mainPanel; + } private void createCenteredTitle(String text, JPanel panel) { JLabel title = new JLabel(text, JLabel.CENTER); @@ -89,10 +104,17 @@ private void createCenteredHyperlink(String text, JPanel panel) { panel.add(hyperlink); } - private void createCenteredLabelOnPanel(String text, JPanel panel) { - JLabel label = new JLabel(text); - label.setHorizontalAlignment(JLabel.CENTER); - panel.add(label); - } + private void createCenteredLabelOnPanel(String text, JPanel panel) { + JLabel label = new JLabel(text); + label.setHorizontalAlignment(JLabel.CENTER); + panel.add(label); + } + + public void appendOutput(String text) { + if (outputArea != null) { + outputArea.append(text); + outputArea.setCaretPosition(outputArea.getDocument().getLength()); + } + } } diff --git a/src/main/java/com/penapereira/example/constructs/decorator/ComponentIF.java b/src/main/java/com/penapereira/example/constructs/decorator/ComponentIF.java new file mode 100644 index 0000000..c8822bd --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/decorator/ComponentIF.java @@ -0,0 +1,5 @@ +package com.penapereira.example.constructs.decorator; + +public interface ComponentIF { + String operation(); +} diff --git a/src/main/java/com/penapereira/example/constructs/decorator/ConcreteComponent.java b/src/main/java/com/penapereira/example/constructs/decorator/ConcreteComponent.java new file mode 100644 index 0000000..b2f5988 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/decorator/ConcreteComponent.java @@ -0,0 +1,8 @@ +package com.penapereira.example.constructs.decorator; + +public class ConcreteComponent implements ComponentIF { + @Override + public String operation() { + return "ConcreteComponent"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/decorator/ConcreteDecoratorA.java b/src/main/java/com/penapereira/example/constructs/decorator/ConcreteDecoratorA.java new file mode 100644 index 0000000..df27b9c --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/decorator/ConcreteDecoratorA.java @@ -0,0 +1,13 @@ +package com.penapereira.example.constructs.decorator; + +public class ConcreteDecoratorA extends Decorator { + + public ConcreteDecoratorA(ComponentIF component) { + super(component); + } + + @Override + public String operation() { + return "ConcreteDecoratorA(" + component.operation() + ")"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/decorator/Decorator.java b/src/main/java/com/penapereira/example/constructs/decorator/Decorator.java new file mode 100644 index 0000000..0236227 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/decorator/Decorator.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.decorator; + +public abstract class Decorator implements ComponentIF { + protected final ComponentIF component; + + protected Decorator(ComponentIF component) { + this.component = component; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunner.java b/src/main/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunner.java new file mode 100644 index 0000000..9316a9e --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunner.java @@ -0,0 +1,25 @@ +package com.penapereira.example.constructs.decorator; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.penapereira.example.constructs.app.ExampleRunnerInterface; + +import com.penapereira.example.constructs.decorator.ComponentIF; + +@Component +public class DecoratorExampleRunner implements ExampleRunnerInterface { + + private static final Logger log = LoggerFactory.getLogger(DecoratorExampleRunner.class); + + @Override + public void runExample() throws Exception { + log.trace("Executing Decorator Pattern Implementation"); + + ComponentIF component = new ConcreteComponent(); + ComponentIF decorated = new ConcreteDecoratorA(component); + + log.trace(" " + decorated.operation()); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductA.java b/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductA.java new file mode 100644 index 0000000..c12ba5d --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductA.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.factory; + +public class ConcreteProductA implements Product { + + @Override + public String name() { + return "Concrete Product A"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductB.java b/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductB.java new file mode 100644 index 0000000..7648cd6 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/factory/ConcreteProductB.java @@ -0,0 +1,9 @@ +package com.penapereira.example.constructs.factory; + +public class ConcreteProductB implements Product { + + @Override + public String name() { + return "Concrete Product B"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/factory/FactoryExampleRunner.java b/src/main/java/com/penapereira/example/constructs/factory/FactoryExampleRunner.java new file mode 100644 index 0000000..21fec97 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/factory/FactoryExampleRunner.java @@ -0,0 +1,26 @@ +package com.penapereira.example.constructs.factory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.penapereira.example.constructs.app.ExampleRunnerInterface; + +@Component +public class FactoryExampleRunner implements ExampleRunnerInterface { + + private static final Logger log = LoggerFactory.getLogger(FactoryExampleRunner.class); + + @Override + public void runExample() throws Exception { + log.trace("Executing Factory Pattern Implementation:"); + + ProductFactory factory = new ProductFactory(); + + Product productA = factory.createProduct("A"); + Product productB = factory.createProduct("B"); + + log.trace(" " + productA.name()); + log.trace(" " + productB.name()); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/factory/Product.java b/src/main/java/com/penapereira/example/constructs/factory/Product.java new file mode 100644 index 0000000..9f9ef09 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/factory/Product.java @@ -0,0 +1,5 @@ +package com.penapereira.example.constructs.factory; + +public interface Product { + String name(); +} diff --git a/src/main/java/com/penapereira/example/constructs/factory/ProductFactory.java b/src/main/java/com/penapereira/example/constructs/factory/ProductFactory.java new file mode 100644 index 0000000..ac4c4be --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/factory/ProductFactory.java @@ -0,0 +1,12 @@ +package com.penapereira.example.constructs.factory; + +public class ProductFactory { + + public Product createProduct(String type) { + return switch (type) { + case "A" -> new ConcreteProductA(); + case "B" -> new ConcreteProductB(); + default -> throw new IllegalArgumentException("Unknown type: " + type); + }; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/templatemethod/AbstractClass.java b/src/main/java/com/penapereira/example/constructs/templatemethod/AbstractClass.java new file mode 100644 index 0000000..89e9712 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/templatemethod/AbstractClass.java @@ -0,0 +1,12 @@ +package com.penapereira.example.constructs.templatemethod; + +public abstract class AbstractClass { + + protected abstract String stepOne(); + + protected abstract String stepTwo(); + + public final String templateMethod() { + return stepOne() + " then " + stepTwo(); + } +} diff --git a/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassA.java b/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassA.java new file mode 100644 index 0000000..30ed916 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassA.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.templatemethod; + +public class ConcreteClassA extends AbstractClass { + + @Override + protected String stepOne() { + return "A step one"; + } + + @Override + protected String stepTwo() { + return "A step two"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassB.java b/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassB.java new file mode 100644 index 0000000..3242514 --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/templatemethod/ConcreteClassB.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.templatemethod; + +public class ConcreteClassB extends AbstractClass { + + @Override + protected String stepOne() { + return "B step one"; + } + + @Override + protected String stepTwo() { + return "B step two"; + } +} diff --git a/src/main/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunner.java b/src/main/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunner.java new file mode 100644 index 0000000..5bbcaed --- /dev/null +++ b/src/main/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunner.java @@ -0,0 +1,24 @@ +package com.penapereira.example.constructs.templatemethod; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.penapereira.example.constructs.app.ExampleRunnerInterface; + +@Component +public class TemplateMethodExampleRunner implements ExampleRunnerInterface { + + private static final Logger log = LoggerFactory.getLogger(TemplateMethodExampleRunner.class); + + @Override + public void runExample() throws Exception { + log.trace("Executing Template Method Pattern Implementation"); + + AbstractClass a = new ConcreteClassA(); + log.trace(" " + a.templateMethod()); + + AbstractClass b = new ConcreteClassB(); + log.trace(" " + b.templateMethod()); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e5a6e1c..44ac060 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -18,5 +18,6 @@ msg.examplesFound=Implemented examples found msg.enableTraceToSeeExamplesDetails= [*] Please enable TRACE log level if you want to see examples output msg.enableDebugToSeeExamplesList= [*] Please enable DEBUG log level if you want to see the examples list +msg.outputTitle=Output msg.separator=------------------------------------------------------------- \ No newline at end of file diff --git a/src/test/java/com/penapereira/example/constructs/CustomSpringBootContextLoader.java b/src/test/java/com/penapereira/example/constructs/CustomSpringBootContextLoader.java deleted file mode 100644 index f285e6f..0000000 --- a/src/test/java/com/penapereira/example/constructs/CustomSpringBootContextLoader.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.penapereira.example.constructs; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.test.context.SpringBootContextLoader; - -public class CustomSpringBootContextLoader extends SpringBootContextLoader { - @Override - protected SpringApplication getSpringApplication() { - SpringApplication application = super.getSpringApplication(); - application.setHeadless(false); - return application; - } -} \ No newline at end of file diff --git a/src/test/java/com/penapereira/example/constructs/JavaPatternsAndConstructsApplicationTests.java b/src/test/java/com/penapereira/example/constructs/JavaPatternsAndConstructsApplicationTests.java deleted file mode 100644 index a7de7a9..0000000 --- a/src/test/java/com/penapereira/example/constructs/JavaPatternsAndConstructsApplicationTests.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.penapereira.example.constructs; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) -@ContextConfiguration(loader = CustomSpringBootContextLoader.class) -public class JavaPatternsAndConstructsApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunnerTests.java new file mode 100644 index 0000000..0d91e57 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.abstractfactory; + +import org.junit.jupiter.api.Test; + +class AbstractFactoryExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new AbstractFactoryExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryTests.java b/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryTests.java new file mode 100644 index 0000000..39eac76 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/abstractfactory/AbstractFactoryTests.java @@ -0,0 +1,16 @@ +package com.penapereira.example.constructs.abstractfactory; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class AbstractFactoryTests { + @Test + void factoriesProduceCorrectProducts() { + AbstractFactory f1 = new Factory1(); + AbstractFactory f2 = new Factory2(); + assertEquals("ProductA1", f1.createProductA().name()); + assertEquals("ProductB1", f1.createProductB().name()); + assertEquals("ProductA2", f2.createProductA().name()); + assertEquals("ProductB2", f2.createProductB().name()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/adapter/AdapterExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/adapter/AdapterExampleRunnerTests.java new file mode 100644 index 0000000..58e73d2 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/adapter/AdapterExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.adapter; + +import org.junit.jupiter.api.Test; + +class AdapterExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new AdapterExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/app/properties/ApplicationPropertiesTests.java b/src/test/java/com/penapereira/example/constructs/app/properties/ApplicationPropertiesTests.java new file mode 100644 index 0000000..00ba77a --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/app/properties/ApplicationPropertiesTests.java @@ -0,0 +1,39 @@ +package com.penapereira.example.constructs.app.properties; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +class ApplicationPropertiesTests { + @Test + void settersAndGettersWork() { + ApplicationProperties props = new ApplicationProperties(); + props.setWindowMarginX(10); + props.setWindowMarginY(20); + props.setLinkColor("#123456"); + props.setLinkColorHover("#abcdef"); + props.setAppIcon(new ClassPathResource("icon.png")); + + assertEquals(10, props.getWindowMarginX()); + assertEquals(20, props.getWindowMarginY()); + assertEquals("#123456", props.getLinkColor()); + assertEquals("#abcdef", props.getLinkColorHover()); + assertEquals("icon.png", props.getAppIcon().getFilename()); + + String s = props.toString(); + assertTrue(s.contains("123456")); + assertNotEquals(0, props.hashCode()); + assertEquals(props, props); + + ApplicationProperties other = new ApplicationProperties(); + other.setWindowMarginX(10); + other.setWindowMarginY(20); + other.setLinkColor("#123456"); + other.setLinkColorHover("#abcdef"); + other.setAppIcon(new ClassPathResource("icon.png")); + assertEquals(props, other); + assertEquals(props.hashCode(), other.hashCode()); + assertNotEquals(props, "bar"); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java b/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java new file mode 100644 index 0000000..723bbe6 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/app/properties/MessagesTests.java @@ -0,0 +1,50 @@ +package com.penapereira.example.constructs.app.properties; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class MessagesTests { + @Test + void settersAndGettersWork() { + Messages m = new Messages(); + m.setGreeting("G"); + m.setWindowTitle("T"); + m.setHomeUrl("U"); + m.setInfo("I"); + m.setExamplesFound("E"); + m.setEnableTraceToSeeExamplesDetails("TD"); + m.setEnableDebugToSeeExamplesList("DL"); + m.setSeparator("-"); + m.setOutputTitle("OT"); + + assertEquals("G", m.getGreeting()); + assertEquals("T", m.getWindowTitle()); + assertEquals("U", m.getHomeUrl()); + assertEquals("I", m.getInfo()); + assertEquals("E", m.getExamplesFound()); + assertEquals("TD", m.getEnableTraceToSeeExamplesDetails()); + assertEquals("DL", m.getEnableDebugToSeeExamplesList()); + assertEquals("-", m.getSeparator()); + assertEquals("OT", m.getOutputTitle()); + + String s = m.toString(); + assertTrue(s.contains("G")); + assertNotEquals(0, m.hashCode()); + assertEquals(m, m); + + Messages other = new Messages(); + other.setGreeting("G"); + other.setWindowTitle("T"); + other.setHomeUrl("U"); + other.setInfo("I"); + other.setExamplesFound("E"); + other.setEnableTraceToSeeExamplesDetails("TD"); + other.setEnableDebugToSeeExamplesList("DL"); + other.setSeparator("-"); + other.setOutputTitle("OT"); + assertEquals(m, other); + assertEquals(m.hashCode(), other.hashCode()); + assertNotEquals(m, "foo"); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java b/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java new file mode 100644 index 0000000..598d2d9 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/app/ui/GuiAppenderTests.java @@ -0,0 +1,44 @@ +package com.penapereira.example.constructs.app.ui; + +import static org.junit.jupiter.api.Assertions.*; + +import java.awt.EventQueue; +import java.lang.reflect.Field; + +import javax.swing.JTextArea; + +import org.junit.jupiter.api.Test; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.LoggingEvent; + +class GuiAppenderTests { + @Test + void appendsMessageToTextArea() throws Exception { + // Allocate a MainWindow instance without triggering the JFrame constructor + Field theUnsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafeField.get(null); + + MainWindow window = (MainWindow) unsafe.allocateInstance(MainWindow.class); + JTextArea area = new JTextArea(); + Field f = MainWindow.class.getDeclaredField("outputArea"); + f.setAccessible(true); + f.set(window, area); + + GuiAppender appender = new GuiAppender(); + Field mw = GuiAppender.class.getDeclaredField("mainWindow"); + mw.setAccessible(true); + mw.set(appender, window); + appender.start(); + + LoggingEvent event = new LoggingEvent(); + event.setLevel(Level.INFO); + event.setMessage("test message"); + + appender.doAppend(event); + EventQueue.invokeAndWait(() -> {}); + + assertEquals("test message" + System.lineSeparator(), area.getText()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/app/ui/HyperlinkMouseListenerTests.java b/src/test/java/com/penapereira/example/constructs/app/ui/HyperlinkMouseListenerTests.java new file mode 100644 index 0000000..150228c --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/app/ui/HyperlinkMouseListenerTests.java @@ -0,0 +1,33 @@ +package com.penapereira.example.constructs.app.ui; + +import static org.junit.jupiter.api.Assertions.*; + +import java.awt.Color; +import java.awt.event.MouseEvent; + +import javax.swing.JLabel; + +import org.junit.jupiter.api.Test; + +import com.penapereira.example.constructs.app.properties.ApplicationProperties; + +class HyperlinkMouseListenerTests { + @Test + void hyperlinkChangesColorAndText() { + ApplicationProperties props = new ApplicationProperties(); + props.setLinkColor("#000000"); + props.setLinkColorHover("#ffffff"); + HyperlinkMouseListener listener = new HyperlinkMouseListener(props); + JLabel label = new JLabel("http://example.com"); + + MouseEvent enter = new MouseEvent(label, MouseEvent.MOUSE_ENTERED, 0, 0, 0, 0, 1, false); + listener.mouseEntered(enter); + assertTrue(label.getText().contains("")); + assertEquals(Color.decode(props.getLinkColorHover()), label.getForeground()); + + MouseEvent exit = new MouseEvent(label, MouseEvent.MOUSE_EXITED, 0, 0, 0, 0, 1, false); + listener.mouseExited(exit); + assertEquals("http://example.com", label.getText()); + assertEquals(Color.decode(props.getLinkColor()), label.getForeground()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunnerTests.java new file mode 100644 index 0000000..675a8f0 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/decorator/DecoratorExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.decorator; + +import org.junit.jupiter.api.Test; + +class DecoratorExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new DecoratorExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/factory/FactoryExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/factory/FactoryExampleRunnerTests.java new file mode 100644 index 0000000..df9940b --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/factory/FactoryExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.factory; + +import org.junit.jupiter.api.Test; + +class FactoryExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new FactoryExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/factory/FactoryTests.java b/src/test/java/com/penapereira/example/constructs/factory/FactoryTests.java new file mode 100644 index 0000000..e77b299 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/factory/FactoryTests.java @@ -0,0 +1,15 @@ +package com.penapereira.example.constructs.factory; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class FactoryTests { + @Test + void factoryCreatesConcreteProducts() { + ProductFactory factory = new ProductFactory(); + Product a = factory.createProduct("A"); + Product b = factory.createProduct("B"); + assertEquals("Concrete Product A", a.name()); + assertEquals("Concrete Product B", b.name()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodExampleRunnerTests.java new file mode 100644 index 0000000..7f4b712 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.factorymethod; + +import org.junit.jupiter.api.Test; + +class FactoryMethodExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new FactoryMethodExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodTests.java b/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodTests.java new file mode 100644 index 0000000..b87ba00 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/factorymethod/FactoryMethodTests.java @@ -0,0 +1,16 @@ +package com.penapereira.example.constructs.factorymethod; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class FactoryMethodTests { + @Test + void productsReturnName() { + GenericProduct a = new ConcreteProductA(); + GenericProduct b = new ConcreteProductB(); + assertEquals("ConcretepProduct A", a.factoryMethod()); + assertEquals("ConcretepProduct B", b.factoryMethod()); + a.build(); + b.build(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/observer/ObserverExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/observer/ObserverExampleRunnerTests.java new file mode 100644 index 0000000..4f4db53 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/observer/ObserverExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.observer; + +import org.junit.jupiter.api.Test; + +class ObserverExampleRunnerTests { + @Test + void runExampleRuns() { + new ObserverExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/observer/ObserverTests.java b/src/test/java/com/penapereira/example/constructs/observer/ObserverTests.java new file mode 100644 index 0000000..b095c25 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/observer/ObserverTests.java @@ -0,0 +1,34 @@ +package com.penapereira.example.constructs.observer; + +import static org.junit.jupiter.api.Assertions.*; + +import java.beans.PropertyChangeEvent; +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.jupiter.api.Test; + +class ObserverTests { + @Test + void observerReceivesEvent() { + Observable subject = new Observable(); + AtomicReference received = new AtomicReference<>(); + subject.addPropertyChangeListener(received::set); + for (int i = 0; i < 5 && received.get() == null; i++) { + subject.doSomethingWith(5); + } + assertNotNull(received.get()); + assertEquals("myProperty", received.get().getPropertyName()); + assertEquals(5, received.get().getOldValue()); + assertTrue(((int) received.get().getNewValue()) > 5); + } + + @Test + void listenerCanBeRemoved() { + Observable subject = new Observable(); + Observer obs = new Observer(); + subject.addPropertyChangeListener(obs); + subject.removePropertyChangeListener(obs); + subject.doSomethingWith(1); // should not throw + assertEquals(0, subject.getSupport().getPropertyChangeListeners().length); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/producerconsumer/ProducerTests.java b/src/test/java/com/penapereira/example/constructs/producerconsumer/ProducerTests.java new file mode 100644 index 0000000..f95e11e --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/producerconsumer/ProducerTests.java @@ -0,0 +1,23 @@ +package com.penapereira.example.constructs.producerconsumer; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; + +import org.junit.jupiter.api.Test; + +class ProducerTests { + @Test + void producerAddsElements() throws InterruptedException { + BlockingQueue queue = new LinkedBlockingDeque<>(3); + Producer producer = new Producer(queue); + Thread t = new Thread(producer); + t.start(); + t.join(); + assertEquals(3, queue.size()); + assertEquals(1, queue.take()); + assertEquals(2, queue.take()); + assertEquals(3, queue.take()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/singleton/SingletonExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/singleton/SingletonExampleRunnerTests.java new file mode 100644 index 0000000..4d45834 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/singleton/SingletonExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.singleton; + +import org.junit.jupiter.api.Test; + +class SingletonExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new SingletonExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/singleton/SingletonTests.java b/src/test/java/com/penapereira/example/constructs/singleton/SingletonTests.java new file mode 100644 index 0000000..b245bdf --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/singleton/SingletonTests.java @@ -0,0 +1,13 @@ +package com.penapereira.example.constructs.singleton; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class SingletonTests { + @Test + void sameInstanceReturned() { + Singleton first = Singleton.instance(); + Singleton second = Singleton.instance(); + assertSame(first, second); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/strategy/StrategyExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/strategy/StrategyExampleRunnerTests.java new file mode 100644 index 0000000..d305de4 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/strategy/StrategyExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.strategy; + +import org.junit.jupiter.api.Test; + +class StrategyExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new StrategyExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/strategy/StrategyTests.java b/src/test/java/com/penapereira/example/constructs/strategy/StrategyTests.java new file mode 100644 index 0000000..582a192 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/strategy/StrategyTests.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.strategy; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class StrategyTests { + @Test + void contextOperationUsesStrategy() { + Context ctx = new Context(new StrategyImpl1()); + assertEquals("Operation with --> Algorithm from Strategy Implementation 1", ctx.operation()); + ctx.setStrategy(new StrategyImpl2()); + assertEquals("Operation with ==> Algorithm from Strategy Implementation 2", ctx.operation()); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunnerTests.java b/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunnerTests.java new file mode 100644 index 0000000..d9159e6 --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodExampleRunnerTests.java @@ -0,0 +1,10 @@ +package com.penapereira.example.constructs.templatemethod; + +import org.junit.jupiter.api.Test; + +class TemplateMethodExampleRunnerTests { + @Test + void runExampleRuns() throws Exception { + new TemplateMethodExampleRunner().runExample(); + } +} diff --git a/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodTests.java b/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodTests.java new file mode 100644 index 0000000..5cebd6b --- /dev/null +++ b/src/test/java/com/penapereira/example/constructs/templatemethod/TemplateMethodTests.java @@ -0,0 +1,14 @@ +package com.penapereira.example.constructs.templatemethod; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class TemplateMethodTests { + @Test + void templateMethodRunsSteps() { + AbstractClass a = new ConcreteClassA(); + assertEquals("A step one then A step two", a.templateMethod()); + AbstractClass b = new ConcreteClassB(); + assertEquals("B step one then B step two", b.templateMethod()); + } +}