From fcaf72fdf8ccfe4da7d4207f6c042d1a43b3d535 Mon Sep 17 00:00:00 2001 From: JoshuaSinglaANU <109902734+JoshuaSinglaANU@users.noreply.github.com> Date: Sun, 20 Nov 2022 23:37:33 +1100 Subject: [PATCH] feature: #1261 Added collecting parameter design pattern (#2134) * #1261 Added base directories, folders, and file for the collecting parameter design pattern. * #1261 Added initial comment * #1261 Added Maven Dependencies * #1261 Added Maven Dependencies * #1261 Finished README.md file * #1261 Added tests * #1261 Code adheres to the standard * #1261 Code adheres to the standard * #1261 Code adheres to the standard * #1261 - Added table to README.md - Explicitly state that result is the collecting parameter - Improved applicability - Separated PrinterItem.java from PrinterQueue.java - Tests work now - Giant comment split * #1261 fixed programmatic example in README.md. * #1261 updated class diagram * #1261 Fixed everything. * #1261 Minor edit to README.md. * #1261 Minor edit to README.md. * #1261 Minor updates. * #1261 Fixed code style. * #1261 Removed getPrinterQueue test * #1261 Removed code smells * #1261 Added UML plugin. * #1261 Dependencies resolved. * #1261 Specified the UML diagram paths. Perhaps this will work. * #1261 pom.xml updated with UML wrapper. Maybe this will create class diagram when built? * #1261 UML added. * #1261 - README.md obeys the YAML requirements - Typo in README.md fixed - UMLWrapper removed from module pom.xml - More comments added Should be able to merge now :) --- collecting-parameter/README.md | 197 ++++++++++++++++++ .../etc/collecting-parameter.urm.png | Bin 0 -> 55073 bytes .../etc/collecting-parameter.urm.puml | 39 ++++ collecting-parameter/pom.xml | 67 ++++++ .../com/iluwatar/collectingparameter/App.java | 138 ++++++++++++ .../collectingparameter/PaperSizes.java | 7 + .../collectingparameter/PrinterItem.java | 34 +++ .../collectingparameter/PrinterQueue.java | 52 +++++ .../iluwatar/collectingparameter/AppTest.java | 39 ++++ .../CollectingParameterTest.java | 55 +++++ .../collectingparameter/PrinterQueueTest.java | 34 +++ pom.xml | 1 + 12 files changed, 663 insertions(+) create mode 100644 collecting-parameter/README.md create mode 100644 collecting-parameter/etc/collecting-parameter.urm.png create mode 100644 collecting-parameter/etc/collecting-parameter.urm.puml create mode 100644 collecting-parameter/pom.xml create mode 100644 collecting-parameter/src/main/java/com/iluwatar/collectingparameter/App.java create mode 100644 collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PaperSizes.java create mode 100644 collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterItem.java create mode 100644 collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterQueue.java create mode 100644 collecting-parameter/src/test/java/com/iluwatar/collectingparameter/AppTest.java create mode 100644 collecting-parameter/src/test/java/com/iluwatar/collectingparameter/CollectingParameterTest.java create mode 100644 collecting-parameter/src/test/java/com/iluwatar/collectingparameter/PrinterQueueTest.java diff --git a/collecting-parameter/README.md b/collecting-parameter/README.md new file mode 100644 index 000000000..a57b8d299 --- /dev/null +++ b/collecting-parameter/README.md @@ -0,0 +1,197 @@ +--- +title: Collecting Parameter +category: Idiom +language: en +tags: +- Generic +--- + +## Name +Collecting Parameter + +## Intent +To store the collaborative result of numerous methods within a collection. + +## Explanation +### Real-world example +Within a large corporate building, there exists a global printer queue that is a collection of all the printing jobs +that are currently pending. Various floors contain different models of printers, each having a different printing +policy. We must construct a program that can continually add appropriate printing jobs to a collection, which is called the *collecting parameter*. + +### In plain words +Instead of having one giant method that contains numerous policies for collecting information into a variable, we can +create numerous smaller functions that each take parameter, and append new information. We can pass the parameter to +all of these smaller functions and by the end, we will have what we wanted originally. This time, the code is cleaner +and easier to understand. Because the larger function has been broken down, the code is also easier to modify as changes +are localised to the smaller functions. + +### Wikipedia says +In the Collecting Parameter idiom a collection (list, map, etc.) is passed repeatedly as a parameter to a method which adds items to the collection. + +### Programmatic example +Coding our example from above, we may use the collection `result` as a collecting parameter. The following restrictions +are implemented: +- If an A4 paper is coloured, it must also be single-sided. All other non-coloured papers are accepted +- A3 papers must be non-coloured and single-sided +- A2 papers must be single-page, single-sided, and non-coloured + +```java +package com.iluwatar.collectingparameter; +import java.util.LinkedList; +import java.util.Queue; +public class App { + static PrinterQueue printerQueue = PrinterQueue.getInstance(); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + /* + Initialising the printer queue with jobs + */ + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A4, 5, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A3, 2, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A2, 5, false, false)); + + /* + This variable is the collecting parameter. + */ + var result = new LinkedList(); + + /* + * Using numerous sub-methods to collaboratively add information to the result collecting parameter + */ + addA4Papers(result); + addA3Papers(result); + addA2Papers(result); + } +} +``` + +We use the `addA4Paper`, `addA3Paper`, and `addA2Paper` methods to populate the `result` collecting parameter with the +appropriate print jobs as per the policy described previously. The three policies are encoded below, + +```java +public class App { + static PrinterQueue printerQueue = PrinterQueue.getInstance(); + /** + * Adds A4 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA4Papers(Queue printerItemsCollection) { + /* + Iterate through the printer queue, and add A4 papers according to the correct policy to the collecting parameter, + which is 'printerItemsCollection' in this case. + */ + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A4)) { + var isColouredAndSingleSided = nextItem.isColour && !nextItem.isDoubleSided; + if (isColouredAndSingleSided) { + printerItemsCollection.add(nextItem); + } else if (!nextItem.isColour) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A3 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA3Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A3)) { + + // Encoding the policy into a Boolean: the A3 paper cannot be coloured and double-sided at the same time + var isNotColouredAndSingleSided = !nextItem.isColour && !nextItem.isDoubleSided; + if (isNotColouredAndSingleSided) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A2 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addA2Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A2)) { + + // Encoding the policy into a Boolean: the A2 paper must be single page, single-sided, and non-coloured. + var isNotColouredSingleSidedAndOnePage = nextItem.pageCount == 1 && !nextItem.isDoubleSided + && !nextItem.isColour; + if (isNotColouredSingleSidedAndOnePage) { + printerItemsCollection.add(nextItem); + } + } + } + } +} +``` + +Each method takes a collecting parameter as an argument. It then adds elements, taken from a global variable, +to this collecting parameter if each element satisfies a given criteria. These methods can have whatever policy the client desires. + +In this programmatic example, three print jobs are added to the queue. Only the first two print jobs should be added to +the collecting parameter as per the policy. The elements of the `result` variable after execution are, + +| paperSize | pageCount | isDoubleSided | isColour | +|-----------|-----------|---------------|----------| +| A4 | 5 | false | false | +| A3 | 2 | false | false | + +which is what we expected. + +## Class diagram +![alt text](./etc/collecting-parameter.urm.png "Collecting Parameter") + +## Applicability +Use the Collecting Parameter design pattern when +- you want to return a collection or object that is the collaborative result of several methods +- You want to simplify a method that accumulates data as the original method is too complex + +## Tutorials +Tutorials for this method are found in: +- [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf) by Joshua Kerivsky +- [Smalltalk Best Practice Patterns](https://ptgmedia.pearsoncmg.com/images/9780134769042/samplepages/013476904X.pdf) by Kent Beck + +## Known uses +Joshua Kerivsky gives a real-world example in his book 'Refactoring to Patterns'. He gives an example of using the +Collecting Parameter Design Pattern to create a `toString()` method for an XML tree. Without using this design pattern, +this would require a bulky function with conditionals and concatenation that would worsen code readability. Such a method +can be broken down into smaller methods, each appending their own set of information to the collecting parameter. + +See this in [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf). + +## Consequences +Pros: +- Makes code more readable +- Avoids 'linkages', where numerous methods reference the same global variable +- Increases maintainability by decomposing larger functions + +Cons: +- May increase code length +- Adds 'layers' of methods + +## Related patterns +- [Compose Methods](https://www.geeksforgeeks.org/composite-design-pattern/) + +## Credits +Following books were used: +- [Refactoring To Patterns](http://www.tarrani.net/RefactoringToPatterns.pdf) by Joshua Kerivsky +- [Smalltalk Best Practice Patterns](https://ptgmedia.pearsoncmg.com/images/9780134769042/samplepages/013476904X.pdf) by Kent Beck +Sites: +- [Wiki](https://wiki.c2.com/?CollectingParameter) diff --git a/collecting-parameter/etc/collecting-parameter.urm.png b/collecting-parameter/etc/collecting-parameter.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..785d6ecc2da1db937e309089917138e578927fa0 GIT binary patch literal 55073 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 literal 0 HcmV?d00001 diff --git a/collecting-parameter/etc/collecting-parameter.urm.puml b/collecting-parameter/etc/collecting-parameter.urm.puml new file mode 100644 index 000000000..06320fa02 --- /dev/null +++ b/collecting-parameter/etc/collecting-parameter.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.collectingparameter { + class App { + ~ printerQueue : PrinterQueue {static} + + App() + + addValidA2Papers(printerItemsCollection : Queue) {static} + + addValidA3Papers(printerItemsCollection : Queue) {static} + + addValidA4Papers(printerItemsCollection : Queue) {static} + + main(args : String[]) {static} + } + ~enum PaperSizes { + + A2 {static} + + A3 {static} + + A4 {static} + + valueOf(name : String) : PaperSizes {static} + + values() : PaperSizes[] {static} + } + class PrinterItem { + ~ isColour : boolean + ~ isDoubleSided : boolean + ~ pageCount : int + ~ paperSize : PaperSizes + + PrinterItem(paperSize : PaperSizes, pageCount : int, isDoubleSided : boolean, isColour : boolean) + } + class PrinterQueue { + ~ currentInstance : PrinterQueue {static} + - printerItemQueue : Queue + - PrinterQueue() + + addPrinterItem(printerItem : PrinterItem) + + emptyQueue() + + getInstance() : PrinterQueue {static} + + getPrinterQueue() : Queue + } +} +PrinterQueue --> "-currentInstance" PrinterQueue +PrinterQueue --> "-printerItemQueue" PrinterItem +App --> "-printerQueue" PrinterQueue +PrinterItem --> "-paperSize" PaperSizes +@enduml \ No newline at end of file diff --git a/collecting-parameter/pom.xml b/collecting-parameter/pom.xml new file mode 100644 index 000000000..8f7fdc2b5 --- /dev/null +++ b/collecting-parameter/pom.xml @@ -0,0 +1,67 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + collecting-parameter + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.collectingparameter.App + + + + + + + + + diff --git a/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/App.java b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/App.java new file mode 100644 index 000000000..93ead620d --- /dev/null +++ b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/App.java @@ -0,0 +1,138 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.collectingparameter; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * The Collecting Parameter Design Pattern aims to return a result that is the collaborative result of several + * methods. This design pattern uses a 'collecting parameter' that is passed to several functions, accumulating results + * as it travels from method-to-method. This is different to the Composed Method design pattern, where a single + * collection is modified via several methods. + * + *

This example is inspired by Kent Beck's example in his book, 'Smalltalk Best Practice Patterns'. The context for this + * situation is that there is a single printer queue {@link PrinterQueue} that holds numerous print jobs + * {@link PrinterItem} that must be distributed to various print centers. + * Each print center has its own requirements and printing limitations. In this example, the following requirements are: + * If an A4 document is coloured, it must also be single-sided. All other non-coloured A4 documents are accepted. + * All A3 documents must be non-coloured and single sided. All A2 documents must be a single page, single sided, and + * non-coloured. + * + *

A collecting parameter (the result variable) is used to filter the global printer queue so that it meets the + * requirements for this centre, + **/ + +public class App { + static PrinterQueue printerQueue = PrinterQueue.getInstance(); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + /* + Initialising the printer queue with jobs + */ + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A4, 5, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A3, 2, false, false)); + printerQueue.addPrinterItem(new PrinterItem(PaperSizes.A2, 5, false, false)); + + /* + This variable is the collecting parameter, and will store the policy abiding print jobs. + */ + var result = new LinkedList(); + + /* + Adding A4, A3, and A2 papers that obey the policy + */ + addValidA4Papers(result); + addValidA3Papers(result); + addValidA2Papers(result); + } + + /** + * Adds A4 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addValidA4Papers(Queue printerItemsCollection) { + /* + Iterate through the printer queue, and add A4 papers according to the correct policy to the collecting parameter, + which is 'printerItemsCollection' in this case. + */ + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A4)) { + var isColouredAndSingleSided = nextItem.isColour && !nextItem.isDoubleSided; + if (isColouredAndSingleSided || !nextItem.isColour) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A3 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addValidA3Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A3)) { + + // Encoding the policy into a Boolean: the A3 paper cannot be coloured and double-sided at the same time + var isNotColouredAndSingleSided = !nextItem.isColour && !nextItem.isDoubleSided; + if (isNotColouredAndSingleSided) { + printerItemsCollection.add(nextItem); + } + } + } + } + + /** + * Adds A2 document jobs to the collecting parameter according to some policy that can be whatever the client + * (the print center) wants. The code is similar to the 'addA4Papers' method. The code can be changed to accommodate + * the wants of the client. + * + * @param printerItemsCollection the collecting parameter + */ + public static void addValidA2Papers(Queue printerItemsCollection) { + for (PrinterItem nextItem : printerQueue.getPrinterQueue()) { + if (nextItem.paperSize.equals(PaperSizes.A2)) { + + // Encoding the policy into a Boolean: the A2 paper must be single page, single-sided, and non-coloured. + var isNotColouredSingleSidedAndOnePage = nextItem.pageCount == 1 && !nextItem.isDoubleSided + && !nextItem.isColour; + if (isNotColouredSingleSidedAndOnePage) { + printerItemsCollection.add(nextItem); + } + } + } + } +} diff --git a/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PaperSizes.java b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PaperSizes.java new file mode 100644 index 000000000..352bf3cc2 --- /dev/null +++ b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PaperSizes.java @@ -0,0 +1,7 @@ +package com.iluwatar.collectingparameter; + +enum PaperSizes { + A2, + A3, + A4 +} diff --git a/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterItem.java b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterItem.java new file mode 100644 index 000000000..629cdb625 --- /dev/null +++ b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterItem.java @@ -0,0 +1,34 @@ +package com.iluwatar.collectingparameter; + +import java.util.Objects; + +/** + * This class represents a Print Item, that should be added to the queue. + **/ +public class PrinterItem { + PaperSizes paperSize; + int pageCount; + boolean isDoubleSided; + boolean isColour; + + /** + * The {@link PrinterItem} constructor. + **/ + public PrinterItem(PaperSizes paperSize, int pageCount, boolean isDoubleSided, boolean isColour) { + if (!Objects.isNull(paperSize)) { + this.paperSize = paperSize; + } else { + throw new IllegalArgumentException(); + } + + if (pageCount > 0) { + this.pageCount = pageCount; + } else { + throw new IllegalArgumentException(); + } + + this.isColour = isColour; + this.isDoubleSided = isDoubleSided; + + } +} diff --git a/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterQueue.java b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterQueue.java new file mode 100644 index 000000000..2408d076c --- /dev/null +++ b/collecting-parameter/src/main/java/com/iluwatar/collectingparameter/PrinterQueue.java @@ -0,0 +1,52 @@ +package com.iluwatar.collectingparameter; + +import java.util.LinkedList; +import java.util.Objects; +import java.util.Queue; + +/** + * This class represents a singleton Printer Queue. It contains a queue that can be filled up with {@link PrinterItem}. + **/ +public class PrinterQueue { + + static PrinterQueue currentInstance = null; + private final Queue printerItemQueue; + + /** + * This class is a singleton. The getInstance method will ensure that only one instance exists at a time. + */ + public static PrinterQueue getInstance() { + if (Objects.isNull(currentInstance)) { + currentInstance = new PrinterQueue(); + } + return currentInstance; + } + + /** + * Empty the printer queue. + */ + public void emptyQueue() { + currentInstance.getPrinterQueue().clear(); + } + + /** + * Private constructor prevents instantiation, unless using the getInstance() method. + */ + private PrinterQueue() { + printerItemQueue = new LinkedList<>(); + } + + public Queue getPrinterQueue() { + return currentInstance.printerItemQueue; + } + + /** + * Adds a single print job to the queue. + * + * @param printerItem The printing job to be added to the queue + */ + public void addPrinterItem(PrinterItem printerItem) { + currentInstance.getPrinterQueue().add(printerItem); + } + +} diff --git a/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/AppTest.java b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/AppTest.java new file mode 100644 index 000000000..57f903777 --- /dev/null +++ b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/AppTest.java @@ -0,0 +1,39 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 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.collectingparameter; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +class AppTest { + /** + * Checks whether {@link App} executes without throwing exception + */ + @Test + void executesWithoutException() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/CollectingParameterTest.java b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/CollectingParameterTest.java new file mode 100644 index 000000000..53b7a4635 --- /dev/null +++ b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/CollectingParameterTest.java @@ -0,0 +1,55 @@ +package com.iluwatar.collectingparameter; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.LinkedList; +import java.util.Queue; + +class CollectingParameterTest { + + @Test + @Timeout(1000) + void testCollectingParameter() { + PrinterQueue printerQueue = PrinterQueue.getInstance(); + printerQueue.emptyQueue(); + + PrinterItem item1 = new PrinterItem(PaperSizes.A4, 1, false, true); + PrinterItem item2 = new PrinterItem(PaperSizes.A4, 10, true, false); + PrinterItem item3 = new PrinterItem(PaperSizes.A4, 4, true, true); + PrinterItem item4 = new PrinterItem(PaperSizes.A3, 9, false, false); + PrinterItem item5 = new PrinterItem(PaperSizes.A3, 3, true, true); + PrinterItem item6 = new PrinterItem(PaperSizes.A3, 3, false, true); + PrinterItem item7 = new PrinterItem(PaperSizes.A3, 3, true, false); + PrinterItem item8 = new PrinterItem(PaperSizes.A2, 1, false, false); + PrinterItem item9 = new PrinterItem(PaperSizes.A2, 2, false, false); + PrinterItem item10 = new PrinterItem(PaperSizes.A2, 1, true, false); + PrinterItem item11 = new PrinterItem(PaperSizes.A2, 1, false, true); + + printerQueue.addPrinterItem(item1); + printerQueue.addPrinterItem(item2); + printerQueue.addPrinterItem(item3); + printerQueue.addPrinterItem(item4); + printerQueue.addPrinterItem(item5); + printerQueue.addPrinterItem(item6); + printerQueue.addPrinterItem(item7); + printerQueue.addPrinterItem(item8); + printerQueue.addPrinterItem(item9); + printerQueue.addPrinterItem(item10); + printerQueue.addPrinterItem(item11); + + Queue result = new LinkedList<>(); + App.addValidA4Papers(result); + App.addValidA3Papers(result); + App.addValidA2Papers(result); + + Queue testResult = new LinkedList<>(); + testResult.add(item1); + testResult.add(item2); + testResult.add(item4); + testResult.add(item8); + + Assertions.assertArrayEquals(testResult.toArray(), result.toArray()); + } +} diff --git a/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/PrinterQueueTest.java b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/PrinterQueueTest.java new file mode 100644 index 000000000..8371732f6 --- /dev/null +++ b/collecting-parameter/src/test/java/com/iluwatar/collectingparameter/PrinterQueueTest.java @@ -0,0 +1,34 @@ +package com.iluwatar.collectingparameter; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import java.util.LinkedList; +import java.util.Queue; + +import static org.junit.jupiter.api.Assertions.*; + +class PrinterQueueTest { + + @Test + @Timeout(1000) + void singletonTest() { + PrinterQueue printerQueue1 = PrinterQueue.getInstance(); + PrinterQueue printerQueue2 = PrinterQueue.getInstance(); + assertSame(printerQueue1, printerQueue2); + } + + @Test() + @Timeout(1000) + void negativePageCount() throws IllegalArgumentException { + Assertions.assertThrows(IllegalArgumentException.class, () -> new PrinterItem(PaperSizes.A4, -1, true, true)); + } + + @Test() + @Timeout(1000) + void nullPageSize() throws IllegalArgumentException { + Assertions.assertThrows(IllegalArgumentException.class, () -> new PrinterItem(null, 1, true, true)); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index d7a16f2cf..dfbd1f62a 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,7 @@ abstract-factory + collecting-parameter monitor tls builder