diff --git a/readonly.csv b/readonly.csv new file mode 100644 index 0000000000..e69de29bb2 diff --git a/report.csv b/report.csv new file mode 100644 index 0000000000..68a1cf5e85 --- /dev/null +++ b/report.csv @@ -0,0 +1,4 @@ +fruit,quantity +apple,160 +banana,115 +pear,140 \ No newline at end of file diff --git a/src/main/java/core/basesyntax/HelloWorld.java b/src/main/java/core/basesyntax/HelloWorld.java deleted file mode 100644 index e758b17650..0000000000 --- a/src/main/java/core/basesyntax/HelloWorld.java +++ /dev/null @@ -1,7 +0,0 @@ -package core.basesyntax; - -/** - * Feel free to remove this class and create your own. - */ -public class HelloWorld { -} diff --git a/src/main/java/core/basesyntax/Main.java b/src/main/java/core/basesyntax/Main.java new file mode 100644 index 0000000000..42b929db7b --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,48 @@ +package core.basesyntax; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.FileReader; +import core.basesyntax.service.FileReaderImpl; +import core.basesyntax.service.ParseService; +import core.basesyntax.service.ParseServiceImpl; +import core.basesyntax.service.PurchaseOperationHandler; +import core.basesyntax.service.RemnantOperationHandler; +import core.basesyntax.service.ReportService; +import core.basesyntax.service.ReportServiceImpl; +import core.basesyntax.service.SupplyOperationHandler; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.OperationStrategyImpl; +import java.io.File; +import java.net.URL; +import java.util.HashMap; +import java.util.List; + +public class Main { + private static final String[] FILE_NAMES = + new String[]{"input1.csv", "input2.csv", "input3.csv"}; + + public static void main(String[] args) { + FileReader fileReader = new FileReaderImpl(); + ParseService parseService = new ParseServiceImpl(); + ReportService reportService = new ReportServiceImpl(); + OperationStrategy operationStrategy = new OperationStrategyImpl(new HashMap<>() {{ + put(FruitTransaction.Operation.BALANCE, new RemnantOperationHandler()); + put(FruitTransaction.Operation.PURCHASE, new PurchaseOperationHandler()); + put(FruitTransaction.Operation.RETURN, new SupplyOperationHandler()); + put(FruitTransaction.Operation.SUPPLY, new SupplyOperationHandler()); + }} + ); + ClassLoader classLoader = Main.class.getClassLoader(); + for (String fileName : FILE_NAMES) { + URL resources = classLoader.getResource(fileName); + List fruitTransactions = parseService.parse( + fileReader.readFromFile(new File(resources.getFile()))); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy + .get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), fruitTransaction.getQuantity()); + } + System.out.println(reportService.generateReport() + System.lineSeparator()); + } + } +} diff --git a/src/main/java/core/basesyntax/dao/FruitDao.java b/src/main/java/core/basesyntax/dao/FruitDao.java new file mode 100644 index 0000000000..4423533946 --- /dev/null +++ b/src/main/java/core/basesyntax/dao/FruitDao.java @@ -0,0 +1,9 @@ +package core.basesyntax.dao; + +public interface FruitDao { + void add(String name, int quantity); + + void set(String name, int quantity); + + void remove(String name, int quantity); +} diff --git a/src/main/java/core/basesyntax/dao/FruitDaoImpl.java b/src/main/java/core/basesyntax/dao/FruitDaoImpl.java new file mode 100644 index 0000000000..b98215973f --- /dev/null +++ b/src/main/java/core/basesyntax/dao/FruitDaoImpl.java @@ -0,0 +1,42 @@ +package core.basesyntax.dao; + +import java.util.HashMap; +import java.util.Map; + +public class FruitDaoImpl implements FruitDao { + private static final Map fruits = new HashMap<>(); + + public static Map getFruits() { + Map fruitsCopy = new HashMap<>(); + for (String key : fruits.keySet()) { + fruitsCopy.put(key, fruits.get(key)); + + } + return fruitsCopy; + } + + @Override + public void add(String name, int quantity) { + if (quantity < 0) { + throw new RuntimeException("Cannot add such quantity: " + quantity); + } + int currentAmount = fruits.getOrDefault(name, 0); + fruits.put(name, currentAmount + quantity); + } + + @Override + public void remove(String name, int quantity) { + if (fruits.get(name) < quantity) { + throw new RuntimeException("Not enough " + name + " to purchase"); + } + fruits.put(name, fruits.get(name) - quantity); + } + + @Override + public void set(String name, int quantity) { + if (quantity < 0) { + throw new RuntimeException("Cannot put such quantity: " + quantity); + } + fruits.put(name, quantity); + } +} diff --git a/src/main/java/core/basesyntax/model/FruitTransaction.java b/src/main/java/core/basesyntax/model/FruitTransaction.java new file mode 100644 index 0000000000..c168dfb5b0 --- /dev/null +++ b/src/main/java/core/basesyntax/model/FruitTransaction.java @@ -0,0 +1,80 @@ +package core.basesyntax.model; + +import java.util.NoSuchElementException; +import java.util.Objects; + +public class FruitTransaction { + private Operation operation; + private String fruit; + private int quantity; + + public FruitTransaction(String fruit, int quantity, Operation operation) { + this.fruit = fruit; + this.quantity = quantity; + this.operation = operation; + } + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } + + public String getFruit() { + return fruit; + } + + public void setFruit(String fruit) { + this.fruit = fruit; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != FruitTransaction.class) { + return false; + } + FruitTransaction fruitTransaction = (FruitTransaction) obj; + return Objects.equals(this.fruit, fruitTransaction.fruit) + && Objects.equals(this.quantity, fruitTransaction.quantity) + && Objects.equals(this.operation, fruitTransaction.operation); + } + + public enum Operation { + BALANCE("b"), + SUPPLY("s"), + PURCHASE("p"), + RETURN("r"); + + private final String operation; + + Operation(String operation) { + this.operation = operation; + } + + public String getOperation() { + return operation; + } + + public static Operation getByCode(String code) { + for (Operation operation : values()) { + if (operation.getOperation().equals(code)) { + return operation; + } + } + throw new NoSuchElementException("Unknown operation: " + code); + } + } +} diff --git a/src/main/java/core/basesyntax/service/FileReader.java b/src/main/java/core/basesyntax/service/FileReader.java new file mode 100644 index 0000000000..b72f897901 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileReader.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import java.io.File; +import java.util.List; + +public interface FileReader { + List readFromFile(File file); +} diff --git a/src/main/java/core/basesyntax/service/FileReaderImpl.java b/src/main/java/core/basesyntax/service/FileReaderImpl.java new file mode 100644 index 0000000000..fb155a20c8 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileReaderImpl.java @@ -0,0 +1,26 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +public class FileReaderImpl implements FileReader { + private static final String SEPARATOR = ","; + private static final int HEADER_INDEX = 0; + private static final int OPERATION_INDEX = 0; + private static final int FRUIT_INDEX = 1; + private static final int AMOUNT_INDEX = 2; + + @Override + public List readFromFile(File file) { + ArrayList fruitTransactions = new ArrayList<>(); + try { + return Files.readAllLines(file.toPath()); + } catch (IOException ioException) { + throw new RuntimeException("Cannot read data from file: " + file, ioException); + } + } +} diff --git a/src/main/java/core/basesyntax/service/FileWriter.java b/src/main/java/core/basesyntax/service/FileWriter.java new file mode 100644 index 0000000000..91dafa12cd --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileWriter.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.io.File; + +public interface FileWriter { + void writeToFile(File file, String report); +} diff --git a/src/main/java/core/basesyntax/service/FileWriterImpl.java b/src/main/java/core/basesyntax/service/FileWriterImpl.java new file mode 100644 index 0000000000..8b54ef6141 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileWriterImpl.java @@ -0,0 +1,17 @@ +package core.basesyntax.service; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class FileWriterImpl implements core.basesyntax.service.FileWriter { + @Override + public void writeToFile(File file, String report) { + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + bufferedWriter.write(report); + } catch (IOException ioException) { + throw new RuntimeException("Cannot write data to file: " + file, ioException); + } + } +} diff --git a/src/main/java/core/basesyntax/service/OperationHandler.java b/src/main/java/core/basesyntax/service/OperationHandler.java new file mode 100644 index 0000000000..5903baea40 --- /dev/null +++ b/src/main/java/core/basesyntax/service/OperationHandler.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface OperationHandler { + void handle(String name, int amount); +} diff --git a/src/main/java/core/basesyntax/service/ParseService.java b/src/main/java/core/basesyntax/service/ParseService.java new file mode 100644 index 0000000000..34196fd903 --- /dev/null +++ b/src/main/java/core/basesyntax/service/ParseService.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; +import java.util.List; + +public interface ParseService { + List parse(List fruits); +} diff --git a/src/main/java/core/basesyntax/service/ParseServiceImpl.java b/src/main/java/core/basesyntax/service/ParseServiceImpl.java new file mode 100644 index 0000000000..a6523e5d0a --- /dev/null +++ b/src/main/java/core/basesyntax/service/ParseServiceImpl.java @@ -0,0 +1,41 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +public class ParseServiceImpl implements ParseService { + private static final String SEPARATOR = ","; + private static final int HEADER_INDEX = 0; + private static final int OPERATION_INDEX = 0; + private static final int FRUIT_INDEX = 1; + private static final int AMOUNT_INDEX = 2; + + @Override + public List parse(List fruits) { + ArrayList fruitTransactions = new ArrayList<>(); + fruits.remove(HEADER_INDEX); + for (String fruit : fruits) { + String[] parsedFruit = fruit.split(SEPARATOR); + try { + int amount = Integer.parseInt(parsedFruit[AMOUNT_INDEX]); + if (amount < 0) { + throw new NumberFormatException(); + } + FruitTransaction.Operation operation + = FruitTransaction.Operation.getByCode(parsedFruit[OPERATION_INDEX]); + fruitTransactions.add(new FruitTransaction(parsedFruit[FRUIT_INDEX], + amount, operation)); + } catch (NumberFormatException numberFormatException) { + throw new RuntimeException("Invalid amount: " + parsedFruit[AMOUNT_INDEX], + numberFormatException); + } catch (NoSuchElementException noSuchElementException) { + throw new RuntimeException("No such operation code: " + + parsedFruit[OPERATION_INDEX], + noSuchElementException); + } + } + return fruitTransactions; + } +} diff --git a/src/main/java/core/basesyntax/service/PurchaseOperationHandler.java b/src/main/java/core/basesyntax/service/PurchaseOperationHandler.java new file mode 100644 index 0000000000..ce50759adb --- /dev/null +++ b/src/main/java/core/basesyntax/service/PurchaseOperationHandler.java @@ -0,0 +1,13 @@ +package core.basesyntax.service; + +import core.basesyntax.dao.FruitDao; +import core.basesyntax.dao.FruitDaoImpl; + +public class PurchaseOperationHandler implements OperationHandler { + private FruitDao fruitDao = new FruitDaoImpl(); + + @Override + public void handle(String name, int amount) { + fruitDao.remove(name, amount); + } +} diff --git a/src/main/java/core/basesyntax/service/RemnantOperationHandler.java b/src/main/java/core/basesyntax/service/RemnantOperationHandler.java new file mode 100644 index 0000000000..9b2a14d9a6 --- /dev/null +++ b/src/main/java/core/basesyntax/service/RemnantOperationHandler.java @@ -0,0 +1,13 @@ +package core.basesyntax.service; + +import core.basesyntax.dao.FruitDao; +import core.basesyntax.dao.FruitDaoImpl; + +public class RemnantOperationHandler implements OperationHandler { + private FruitDao fruitDao = new FruitDaoImpl(); + + @Override + public void handle(String name, int amount) { + fruitDao.set(name, amount); + } +} diff --git a/src/main/java/core/basesyntax/service/ReportService.java b/src/main/java/core/basesyntax/service/ReportService.java new file mode 100644 index 0000000000..0c9cafce0b --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportService.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface ReportService { + public String generateReport(); +} diff --git a/src/main/java/core/basesyntax/service/ReportServiceImpl.java b/src/main/java/core/basesyntax/service/ReportServiceImpl.java new file mode 100644 index 0000000000..ce68018cce --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportServiceImpl.java @@ -0,0 +1,21 @@ +package core.basesyntax.service; + +import core.basesyntax.dao.FruitDaoImpl; +import java.util.TreeSet; + +public class ReportServiceImpl implements ReportService { + private static final String SEPARATOR = ","; + private static final String HEADER = "fruit,quantity"; + private FruitDaoImpl fruitDao = new FruitDaoImpl(); + + @Override + public String generateReport() { + StringBuilder stringBuilder = new StringBuilder(HEADER); + for (String key : new TreeSet<>(fruitDao.getFruits().keySet())) { + stringBuilder.append(System.lineSeparator()) + .append(key) + .append(SEPARATOR).append(fruitDao.getFruits().get(key)); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/core/basesyntax/service/SupplyOperationHandler.java b/src/main/java/core/basesyntax/service/SupplyOperationHandler.java new file mode 100644 index 0000000000..b0c9b8d029 --- /dev/null +++ b/src/main/java/core/basesyntax/service/SupplyOperationHandler.java @@ -0,0 +1,13 @@ +package core.basesyntax.service; + +import core.basesyntax.dao.FruitDao; +import core.basesyntax.dao.FruitDaoImpl; + +public class SupplyOperationHandler implements OperationHandler { + private FruitDao fruitDao = new FruitDaoImpl(); + + @Override + public void handle(String name, int amount) { + fruitDao.add(name, amount); + } +} diff --git a/src/main/java/core/basesyntax/strategy/OperationStrategy.java b/src/main/java/core/basesyntax/strategy/OperationStrategy.java new file mode 100644 index 0000000000..9f916758f5 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationStrategy.java @@ -0,0 +1,8 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; + +public interface OperationStrategy { + OperationHandler get(FruitTransaction.Operation operation); +} diff --git a/src/main/java/core/basesyntax/strategy/OperationStrategyImpl.java b/src/main/java/core/basesyntax/strategy/OperationStrategyImpl.java new file mode 100644 index 0000000000..2c69b3aa41 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationStrategyImpl.java @@ -0,0 +1,20 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class OperationStrategyImpl implements OperationStrategy { + + private Map operationHandlerMap; + + public OperationStrategyImpl(Map operationHandlerMap) { + this.operationHandlerMap = operationHandlerMap; + } + + @Override + public OperationHandler get(FruitTransaction.Operation operation) { + return operationHandlerMap.get(operation); + } +} diff --git a/src/main/resources/input1.csv b/src/main/resources/input1.csv new file mode 100644 index 0000000000..c771f259d3 --- /dev/null +++ b/src/main/resources/input1.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,20 +b,apple,100 +s,banana,100 +p,banana,13 +r,apple,10 +p,apple,20 +p,banana,5 +s,banana,50 \ No newline at end of file diff --git a/src/main/resources/input2.csv b/src/main/resources/input2.csv new file mode 100644 index 0000000000..7768d43f34 --- /dev/null +++ b/src/main/resources/input2.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,200 +b,apple,150 +p,banana,100 +s,banana,25 +r,apple,10 +r,banana,20 +p,banana,5 +s,banana,15 \ No newline at end of file diff --git a/src/main/resources/input3.csv b/src/main/resources/input3.csv new file mode 100644 index 0000000000..5d46a4fb89 --- /dev/null +++ b/src/main/resources/input3.csv @@ -0,0 +1,11 @@ +type,fruit,quantity +b,pear,200 +b,apple,150 +b,banana,100 +p,pear,80 +s,banana,25 +r,apple,10 +r,pear,20 +p,banana,5 +s,banana,15 +p,banana,20 \ No newline at end of file diff --git a/src/main/resources/invalid1.csv b/src/main/resources/invalid1.csv new file mode 100644 index 0000000000..dd366ec01d --- /dev/null +++ b/src/main/resources/invalid1.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,200 +g,apple,150 +p,banana,100 +c,banana,25 +r,apple,10 +r,banana,20 +p,banana,5 +s,banana,15 \ No newline at end of file diff --git a/src/main/resources/invalid2.csv b/src/main/resources/invalid2.csv new file mode 100644 index 0000000000..2180b05d39 --- /dev/null +++ b/src/main/resources/invalid2.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,20 +b,apple,100 +s,banana,-2 +p,banana,hello +r,apple,-25 +p,apple,20 +p,banana,5 +s,banana,50 \ No newline at end of file diff --git a/src/test/java/core/basesyntax/HelloWorldTest.java b/src/test/java/core/basesyntax/HelloWorldTest.java deleted file mode 100644 index c4a0df68d7..0000000000 --- a/src/test/java/core/basesyntax/HelloWorldTest.java +++ /dev/null @@ -1,7 +0,0 @@ -package core.basesyntax; - -/** - * Feel free to remove this class and create your own. - */ -public class HelloWorldTest { -} diff --git a/src/test/java/core/basesyntax/dao/FruitDaoImplTest.java b/src/test/java/core/basesyntax/dao/FruitDaoImplTest.java new file mode 100644 index 0000000000..081117eb0d --- /dev/null +++ b/src/test/java/core/basesyntax/dao/FruitDaoImplTest.java @@ -0,0 +1,60 @@ +package core.basesyntax.dao; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class FruitDaoImplTest { + private static final int VALID_AMOUNT = 15; + private static final int INVALID_AMOUNT = -1; + private static FruitDao fruitDao; + + @BeforeAll + static void beforeAll() { + fruitDao = new FruitDaoImpl(); + } + + @BeforeEach + void setUp() { + fruitDao.set("apple", VALID_AMOUNT); + } + + @Test + void setInvalidAmount_Not_Ok() { + assertThrows(RuntimeException.class, () -> fruitDao.set("orange", INVALID_AMOUNT)); + } + + @Test + void setValidAmount_Ok() { + fruitDao.set("banana", VALID_AMOUNT); + Integer actual = FruitDaoImpl.getFruits().get("banana"); + assertEquals(VALID_AMOUNT, actual); + } + + @Test + void addInvalidAmount_Not_Ok() { + assertThrows(RuntimeException.class, () -> fruitDao.add("apple", INVALID_AMOUNT)); + } + + @Test + void addValidAmount_Ok() { + fruitDao.add("apple", VALID_AMOUNT); + Integer actual = FruitDaoImpl.getFruits().get("apple"); + assertEquals(VALID_AMOUNT + VALID_AMOUNT, actual); + } + + @Test + void removeInvalidAmount_Not_Ok() { + assertThrows(RuntimeException.class, () -> fruitDao.remove("apple", Integer.MAX_VALUE)); + } + + @Test + void removeValidAmount_Ok() { + fruitDao.remove("apple", VALID_AMOUNT); + Integer actual = FruitDaoImpl.getFruits().get("apple"); + assertEquals(0, actual); + } +} diff --git a/src/test/java/core/basesyntax/service/FileReaderImplTest.java b/src/test/java/core/basesyntax/service/FileReaderImplTest.java new file mode 100644 index 0000000000..9b2028744d --- /dev/null +++ b/src/test/java/core/basesyntax/service/FileReaderImplTest.java @@ -0,0 +1,68 @@ +package core.basesyntax.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class FileReaderImplTest { + private static FileReader fileReader; + private static final String INPUT_1_FILE_NAME = "input1.csv"; + private static final String INPUT_2_FILE_NAME = "input2.csv"; + private static final String INPUT_3_FILE_NAME = "input3.csv"; + private static final String INVALID_FILE_NAME = "input4.csv"; + private static ClassLoader classLoader; + + @BeforeAll + static void beforeAll() { + classLoader = FileReaderImplTest.class.getClassLoader(); + fileReader = new FileReaderImpl(); + } + + @Test + void readFromFile_Not_Ok() { + assertThrows(RuntimeException.class, () -> + fileReader.readFromFile(new File(INVALID_FILE_NAME))); + } + + @Test + void readFromInput1File_Ok() { + URL resources = classLoader.getResource(INPUT_1_FILE_NAME); + List actual = fileReader.readFromFile(new File(resources.getFile())); + List expected = new ArrayList<>(List.of("type,fruit,quantity", + "b,banana,20", "b,apple,100", "s,banana,100", + "p,banana,13", "r,apple,10", "p,apple,20", + "p,banana,5", "s,banana,50")); + assertEquals(expected, actual); + } + + @Test + void readFromInput2File_Ok() { + URL resources = classLoader.getResource(INPUT_2_FILE_NAME); + List actual = fileReader.readFromFile(getFilefromUrl(resources)); + List expected = new ArrayList<>(List.of("type,fruit,quantity", + "b,banana,200", "b,apple,150", "p,banana,100", "s,banana,25", + "r,apple,10", "r,banana,20", "p,banana,5", "s,banana,15")); + assertEquals(expected, actual); + } + + @Test + void readFromInput3File_Ok() { + URL resources = classLoader.getResource(INPUT_3_FILE_NAME); + List actual = fileReader.readFromFile(getFilefromUrl(resources)); + List expected = new ArrayList<>(List.of("type,fruit,quantity", + "b,pear,200", "b,apple,150", "b,banana,100", "p,pear,80", + "s,banana,25", "r,apple,10", "r,pear,20", "p,banana,5", + "s,banana,15", "p,banana,20")); + assertEquals(expected, actual); + } + + private static File getFilefromUrl(URL resources) { + return new File(resources.getFile()); + } +} diff --git a/src/test/java/core/basesyntax/service/FileWriterImplTest.java b/src/test/java/core/basesyntax/service/FileWriterImplTest.java new file mode 100644 index 0000000000..157b5dcc94 --- /dev/null +++ b/src/test/java/core/basesyntax/service/FileWriterImplTest.java @@ -0,0 +1,47 @@ +package core.basesyntax.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class FileWriterImplTest { + private static final String SEPARATOR = ","; + private static final String HEADER = "fruit,quantity"; + private static FileWriter fileWriter; + private static FileReader fileReader; + private static final String READ_ONLY_FILE_NAME = "readonly.csv"; + private static final String FILE_NAME = "report.csv"; + private static final String REPORT = HEADER + System.lineSeparator() + + "apple" + SEPARATOR + 160 + System.lineSeparator() + + "banana" + SEPARATOR + 115 + System.lineSeparator() + + "pear" + SEPARATOR + 140; + + @BeforeAll + static void beforeAll() { + fileWriter = new FileWriterImpl(); + fileReader = new FileReaderImpl(); + } + + @Test + void writeToFile_Ok() { + File file = (new File(FILE_NAME)); + fileWriter.writeToFile(file, REPORT); + List expected = new ArrayList<>(List.of(HEADER, + "apple" + SEPARATOR + 160, + "banana" + SEPARATOR + 115, + "pear" + SEPARATOR + 140)); + List actual = fileReader.readFromFile(file); + assertEquals(expected, actual); + } + + @Test + void writeToReadOnlyFile_Not_Ok() { + assertThrows(RuntimeException.class, () -> + fileWriter.writeToFile(new File(READ_ONLY_FILE_NAME), REPORT)); + } +} diff --git a/src/test/java/core/basesyntax/service/OperationHandlerImplTest.java b/src/test/java/core/basesyntax/service/OperationHandlerImplTest.java new file mode 100644 index 0000000000..f5cb467789 --- /dev/null +++ b/src/test/java/core/basesyntax/service/OperationHandlerImplTest.java @@ -0,0 +1,81 @@ +package core.basesyntax.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import core.basesyntax.dao.FruitDaoImpl; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.OperationStrategyImpl; +import java.io.File; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class OperationHandlerImplTest { + private static FileReader fileReader; + private static ParseService parseService; + private static OperationStrategy operationStrategy; + private static final String INPUT_1_FILE_NAME = "input1.csv"; + private static final String INPUT_2_FILE_NAME = "input2.csv"; + private static final String INPUT_3_FILE_NAME = "input3.csv"; + private static ClassLoader classLoader; + + @BeforeAll + static void beforeAll() { + classLoader = FileReaderImplTest.class.getClassLoader(); + fileReader = new FileReaderImpl(); + parseService = new ParseServiceImpl(); + operationStrategy = new OperationStrategyImpl(new HashMap<>() {{ + put(FruitTransaction.Operation.BALANCE, new RemnantOperationHandler()); + put(FruitTransaction.Operation.PURCHASE, new PurchaseOperationHandler()); + put(FruitTransaction.Operation.RETURN, new SupplyOperationHandler()); + put(FruitTransaction.Operation.SUPPLY, new SupplyOperationHandler()); + }} + ); + } + + @Test + void handleInput1File_Ok() { + URL resources = classLoader.getResource(INPUT_1_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + assertEquals(FruitDaoImpl.getFruits().get("banana"), 152); + assertEquals(FruitDaoImpl.getFruits().get("apple"), 90); + } + + @Test + void handleInput2File_Ok() { + URL resources = classLoader.getResource(INPUT_2_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + assertEquals(FruitDaoImpl.getFruits().get("banana"), 155); + assertEquals(FruitDaoImpl.getFruits().get("apple"), 160); + } + + @Test + void handleInput3File_Ok() { + URL resources = classLoader.getResource(INPUT_3_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + assertEquals(FruitDaoImpl.getFruits().get("banana"), 115); + assertEquals(FruitDaoImpl.getFruits().get("apple"), 160); + assertEquals(FruitDaoImpl.getFruits().get("pear"), 140); + } +} diff --git a/src/test/java/core/basesyntax/service/ParseServiceImplTest.java b/src/test/java/core/basesyntax/service/ParseServiceImplTest.java new file mode 100644 index 0000000000..ceec232b8c --- /dev/null +++ b/src/test/java/core/basesyntax/service/ParseServiceImplTest.java @@ -0,0 +1,97 @@ +package core.basesyntax.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import core.basesyntax.model.FruitTransaction; +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class ParseServiceImplTest { + private static FileReader fileReader; + private static ParseService parseService; + private static final String INPUT_1_FILE_NAME = "input1.csv"; + private static final String INPUT_2_FILE_NAME = "input2.csv"; + private static final String INPUT_3_FILE_NAME = "input3.csv"; + private static final String INVALID_OPERATION_FILE_NAME = "invalid1.csv"; + private static final String INVALID_QUANTITY_FILE_NAME = "invalid2.csv"; + private static ClassLoader classLoader; + + @BeforeAll + static void beforeAll() { + classLoader = FileReaderImplTest.class.getClassLoader(); + fileReader = new FileReaderImpl(); + parseService = new ParseServiceImpl(); + } + + @Test + void parseInput1File_Ok() { + URL resources = classLoader.getResource(INPUT_1_FILE_NAME); + List result = fileReader.readFromFile(new File(resources.getFile())); + List expected = new ArrayList<>(List.of( + new FruitTransaction("banana", 20, FruitTransaction.Operation.BALANCE), + new FruitTransaction("apple", 100, FruitTransaction.Operation.BALANCE), + new FruitTransaction("banana", 100, FruitTransaction.Operation.SUPPLY), + new FruitTransaction("banana", 13, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("apple", 10, FruitTransaction.Operation.RETURN), + new FruitTransaction("apple", 20, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 5, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 50, FruitTransaction.Operation.SUPPLY))); + List actual = parseService.parse(result); + assertEquals(expected, actual); + } + + @Test + void parseInput2File_Ok() { + URL resources = classLoader.getResource(INPUT_2_FILE_NAME); + List result = fileReader.readFromFile(new File(resources.getFile())); + List expected = new ArrayList<>(List.of( + new FruitTransaction("banana", 200, FruitTransaction.Operation.BALANCE), + new FruitTransaction("apple", 150, FruitTransaction.Operation.BALANCE), + new FruitTransaction("banana", 100, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 25, FruitTransaction.Operation.SUPPLY), + new FruitTransaction("apple", 10, FruitTransaction.Operation.RETURN), + new FruitTransaction("banana", 20, FruitTransaction.Operation.RETURN), + new FruitTransaction("banana", 5, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 15, FruitTransaction.Operation.SUPPLY))); + List actual = parseService.parse(result); + assertEquals(expected, actual); + } + + @Test + void parseInput3File_Ok() { + URL resources = classLoader.getResource(INPUT_3_FILE_NAME); + List result = fileReader.readFromFile(new File(resources.getFile())); + List expected = new ArrayList<>(List.of( + new FruitTransaction("pear", 200, FruitTransaction.Operation.BALANCE), + new FruitTransaction("apple", 150, FruitTransaction.Operation.BALANCE), + new FruitTransaction("banana", 100, FruitTransaction.Operation.BALANCE), + new FruitTransaction("pear", 80, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 25, FruitTransaction.Operation.SUPPLY), + new FruitTransaction("apple", 10, FruitTransaction.Operation.RETURN), + new FruitTransaction("pear", 20, FruitTransaction.Operation.RETURN), + new FruitTransaction("banana", 5, FruitTransaction.Operation.PURCHASE), + new FruitTransaction("banana", 15, FruitTransaction.Operation.SUPPLY), + new FruitTransaction("banana", 20, FruitTransaction.Operation.PURCHASE))); + List actual = parseService.parse(result); + assertEquals(expected, actual); + } + + @Test + void parseInvalidOperationFile_Not_Ok() { + URL resources = classLoader.getResource(INVALID_OPERATION_FILE_NAME); + List result = fileReader.readFromFile(new File(resources.getFile())); + assertThrows(RuntimeException.class, () -> parseService.parse(result)); + } + + @Test + void parseInvalidQuantityFile_Not_Ok() { + URL resources = classLoader.getResource(INVALID_QUANTITY_FILE_NAME); + List result = fileReader.readFromFile(new File(resources.getFile())); + assertThrows(RuntimeException.class, () -> parseService.parse(result)); + } +} diff --git a/src/test/java/core/basesyntax/service/ReportServiceImplTest.java b/src/test/java/core/basesyntax/service/ReportServiceImplTest.java new file mode 100644 index 0000000000..ec095356bb --- /dev/null +++ b/src/test/java/core/basesyntax/service/ReportServiceImplTest.java @@ -0,0 +1,102 @@ +package core.basesyntax.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.OperationStrategyImpl; +import java.io.File; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ReportServiceImplTest { + private static FileReader fileReader; + private static ParseService parseService; + private static OperationStrategy operationStrategy; + private static ReportService reportService; + private static final String SEPARATOR = ","; + private static final String HEADER = "fruit,quantity"; + private static final String INPUT_1_FILE_NAME = "input1.csv"; + private static final String INPUT_2_FILE_NAME = "input2.csv"; + private static final String INPUT_3_FILE_NAME = "input3.csv"; + private static ClassLoader classLoader; + + @BeforeAll + static void beforeAll() { + classLoader = FileReaderImplTest.class.getClassLoader(); + fileReader = new FileReaderImpl(); + parseService = new ParseServiceImpl(); + reportService = new ReportServiceImpl(); + operationStrategy = new OperationStrategyImpl(new HashMap<>() {{ + put(FruitTransaction.Operation.BALANCE, new RemnantOperationHandler()); + put(FruitTransaction.Operation.PURCHASE, new PurchaseOperationHandler()); + put(FruitTransaction.Operation.RETURN, new SupplyOperationHandler()); + put(FruitTransaction.Operation.SUPPLY, new SupplyOperationHandler()); + }} + ); + } + + @Test + @Order(3) + void generateReportInput1File_Ok() { + URL resources = classLoader.getResource(INPUT_1_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + String actual = reportService.generateReport(); + String expected = HEADER + System.lineSeparator() + + "apple" + SEPARATOR + 90 + System.lineSeparator() + + "banana" + SEPARATOR + 152 + System.lineSeparator() + + "pear" + SEPARATOR + 140; + assertEquals(expected, actual); + } + + @Test + @Order(2) + void generateReportInput2File_Ok() { + URL resources = classLoader.getResource(INPUT_2_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + String actual = reportService.generateReport(); + String expected = HEADER + System.lineSeparator() + + "apple" + SEPARATOR + 160 + System.lineSeparator() + + "banana" + SEPARATOR + 155 + System.lineSeparator() + + "pear" + SEPARATOR + 140; + assertEquals(expected, actual); + } + + @Test + @Order(1) + void generateReportInput3File_Ok() { + URL resources = classLoader.getResource(INPUT_3_FILE_NAME); + List readFromFile = fileReader.readFromFile(new File(resources.getFile())); + List fruitTransactions = parseService.parse(readFromFile); + for (FruitTransaction fruitTransaction : fruitTransactions) { + operationStrategy.get(fruitTransaction.getOperation()) + .handle(fruitTransaction.getFruit(), + fruitTransaction.getQuantity()); + } + String actual = reportService.generateReport(); + String expected = HEADER + System.lineSeparator() + + "apple" + SEPARATOR + 160 + System.lineSeparator() + + "banana" + SEPARATOR + 115 + System.lineSeparator() + + "pear" + SEPARATOR + 140; + assertEquals(expected, actual); + } +} diff --git a/src/test/java/core/basesyntax/strategy/OperationStrategyImplTest.java b/src/test/java/core/basesyntax/strategy/OperationStrategyImplTest.java new file mode 100644 index 0000000000..74f915c20f --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/OperationStrategyImplTest.java @@ -0,0 +1,50 @@ +package core.basesyntax.strategy; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.PurchaseOperationHandler; +import core.basesyntax.service.RemnantOperationHandler; +import core.basesyntax.service.SupplyOperationHandler; +import java.util.HashMap; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class OperationStrategyImplTest { + private static OperationStrategy operationStrategy; + + @BeforeAll + static void beforeAll() { + operationStrategy = new OperationStrategyImpl(new HashMap<>() {{ + put(FruitTransaction.Operation.BALANCE, new RemnantOperationHandler()); + put(FruitTransaction.Operation.PURCHASE, new PurchaseOperationHandler()); + put(FruitTransaction.Operation.RETURN, new SupplyOperationHandler()); + put(FruitTransaction.Operation.SUPPLY, new SupplyOperationHandler()); + }} + ); + } + + @Test + void getBalanceOperationHandler_Ok() { + assertTrue(operationStrategy.get(FruitTransaction.Operation.BALANCE) + instanceof RemnantOperationHandler); + } + + @Test + void getSupplyOperationHandler_Ok() { + assertTrue(operationStrategy.get(FruitTransaction.Operation.SUPPLY) + instanceof SupplyOperationHandler); + } + + @Test + void getPurchaseOperationHandler_Ok() { + assertTrue(operationStrategy.get(FruitTransaction.Operation.PURCHASE) + instanceof PurchaseOperationHandler); + } + + @Test + void getReturnOperationHandler_Ok() { + assertTrue(operationStrategy.get(FruitTransaction.Operation.RETURN) + instanceof SupplyOperationHandler); + } +}