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..86ecf1d7de --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,66 @@ +package core.basesyntax; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.service.CsvParseService; +import core.basesyntax.service.FileReadService; +import core.basesyntax.service.FileWriteService; +import core.basesyntax.service.ReportService; +import core.basesyntax.service.imp.CsvParser; +import core.basesyntax.service.imp.FileReadServiceImp; +import core.basesyntax.service.imp.FileWriteServiceImp; +import core.basesyntax.service.imp.Reporter; +import core.basesyntax.strategy.OperationHandler; +import core.basesyntax.strategy.OperationsStrategy; +import core.basesyntax.strategy.handlers.BalanceOperationHandler; +import core.basesyntax.strategy.handlers.PurchaseOperationHandler; +import core.basesyntax.strategy.handlers.ReturnOperationHandler; +import core.basesyntax.strategy.handlers.SupplyOperationHandler; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Main { + private static final String NAME_SOURCE_FILE = "SourceFile.txt"; + private static final String PATH_SOURCE_FILE = "src/main/resources/" + NAME_SOURCE_FILE; + private static final String NAME_CONSUMER_FILE = "ConsumerFile.txt"; + private static final String PATH_CONSUMER_FILE = "src/main/resources/" + NAME_CONSUMER_FILE; + private static final Map storage; + private static final FileReadService fileReadService; + private static final CsvParseService csvParseService; + private static final Map strategies; + private static final StorageDao storageDao; + private static final OperationsStrategy operationsStrategy; + private static final ReportService reportService; + private static final FileWriteService fileWriteService; + + static { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + fileReadService = new FileReadServiceImp(); + csvParseService = new CsvParser(); + strategies = Map.of(GoodsOperation.TransactionType.BALANCE, + new BalanceOperationHandler(storageDao), + GoodsOperation.TransactionType.PURCHASE, + new PurchaseOperationHandler(storageDao), + GoodsOperation.TransactionType.RETURN, + new ReturnOperationHandler(storageDao), + GoodsOperation.TransactionType.SUPPLY, + new SupplyOperationHandler(storageDao)); + operationsStrategy = new OperationsStrategy(strategies); + reportService = new Reporter(storageDao); + fileWriteService = new FileWriteServiceImp(); + } + + public static void main(String[] args) { + List parsedLines = fileReadService.readFilesLines(PATH_SOURCE_FILE); + List operationsList = csvParseService + .listOperationsFromCsv(parsedLines); + for (GoodsOperation operation : operationsList) { + operationsStrategy.handleOperation(operation); + } + List goodsStockCsvReport = reportService.getGoodsStockCsv(); + fileWriteService.writeCsvToFile(goodsStockCsvReport, PATH_CONSUMER_FILE); + } +} diff --git a/src/main/java/core/basesyntax/db/dao/StorageDao.java b/src/main/java/core/basesyntax/db/dao/StorageDao.java new file mode 100644 index 0000000000..9560364316 --- /dev/null +++ b/src/main/java/core/basesyntax/db/dao/StorageDao.java @@ -0,0 +1,11 @@ +package core.basesyntax.db.dao; + +import java.util.Map; + +public interface StorageDao { + Integer getQuantityGoods(String goods); + + void setQuantityGoods(String goods, Integer newQuantity); + + Map getStock(); +} diff --git a/src/main/java/core/basesyntax/db/dao/StorageDaoImp.java b/src/main/java/core/basesyntax/db/dao/StorageDaoImp.java new file mode 100644 index 0000000000..5fc55d93be --- /dev/null +++ b/src/main/java/core/basesyntax/db/dao/StorageDaoImp.java @@ -0,0 +1,27 @@ +package core.basesyntax.db.dao; + +import java.util.HashMap; +import java.util.Map; + +public class StorageDaoImp implements StorageDao { + private final Map storage; + + public StorageDaoImp(Map storage) { + this.storage = storage; + } + + @Override + public Integer getQuantityGoods(String goods) { + return storage.get(goods); + } + + @Override + public void setQuantityGoods(String goods, Integer newQuantity) { + storage.put(goods, newQuantity); + } + + @Override + public Map getStock() { + return new HashMap<>(storage); + } +} diff --git a/src/main/java/core/basesyntax/model/GoodsOperation.java b/src/main/java/core/basesyntax/model/GoodsOperation.java new file mode 100644 index 0000000000..8485bf67ea --- /dev/null +++ b/src/main/java/core/basesyntax/model/GoodsOperation.java @@ -0,0 +1,73 @@ +package core.basesyntax.model; + +import java.util.Objects; + +public class GoodsOperation { + private final TransactionType transactionType; + private final String item; + private final int quantity; + + public GoodsOperation(TransactionType transactionType, String item, int quantity) { + this.transactionType = transactionType; + this.item = item; + this.quantity = quantity; + } + + public String getItem() { + return item; + } + + public TransactionType getTransactionType() { + return transactionType; + } + + public int getQuantity() { + return quantity; + } + + public enum TransactionType { + BALANCE("b"), + SUPPLY("s"), + PURCHASE("p"), + RETURN("r"); + private final String typesCode; + + TransactionType(String code) { + this.typesCode = code; + } + + public static TransactionType getByCode(String code) { + for (TransactionType type : TransactionType.values()) { + if (type.typesCode.equals(code)) { + return type; + } + } + throw new RuntimeException("Can't find operation type: " + code); + } + } + + @Override + public boolean equals(Object operation) { + if (operation == null) { + return false; + } + if (operation == this) { + return true; + } + if (operation.getClass().equals(GoodsOperation.class)) { + GoodsOperation current = (GoodsOperation) operation; + return (transactionType == current.transactionType) + && (Objects.equals(item, current.item)) + && (quantity == current.quantity); + } + return false; + } + + @Override + public int hashCode() { + int result = transactionType != null ? transactionType.hashCode() : 0; + result = 31 * result + (item != null ? item.hashCode() : 0); + result = 31 * result + quantity; + return result; + } +} diff --git a/src/main/java/core/basesyntax/service/CsvParseService.java b/src/main/java/core/basesyntax/service/CsvParseService.java new file mode 100644 index 0000000000..c4424d60e0 --- /dev/null +++ b/src/main/java/core/basesyntax/service/CsvParseService.java @@ -0,0 +1,10 @@ +package core.basesyntax.service; + +import core.basesyntax.model.GoodsOperation; +import java.util.List; + +public interface CsvParseService { + List listOperationsFromCsv(List csvOperations); + + GoodsOperation convertToOperationFromCsv(String operation); +} diff --git a/src/main/java/core/basesyntax/service/FileReadService.java b/src/main/java/core/basesyntax/service/FileReadService.java new file mode 100644 index 0000000000..157d5ae962 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileReadService.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface FileReadService { + List readFilesLines(String path); +} diff --git a/src/main/java/core/basesyntax/service/FileWriteService.java b/src/main/java/core/basesyntax/service/FileWriteService.java new file mode 100644 index 0000000000..501726ef70 --- /dev/null +++ b/src/main/java/core/basesyntax/service/FileWriteService.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface FileWriteService { + void writeCsvToFile(List text, String path); +} 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..5db35267dc --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportService.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface ReportService { + List getGoodsStockCsv(); +} diff --git a/src/main/java/core/basesyntax/service/imp/CsvParser.java b/src/main/java/core/basesyntax/service/imp/CsvParser.java new file mode 100644 index 0000000000..2a432e15fb --- /dev/null +++ b/src/main/java/core/basesyntax/service/imp/CsvParser.java @@ -0,0 +1,40 @@ +package core.basesyntax.service.imp; + +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.service.CsvParseService; +import java.util.ArrayList; +import java.util.List; + +public class CsvParser implements CsvParseService { + private static final String LINE_DIVIDER = ","; + private static final int OPERATION_TYPE_INDEX = 0; + private static final int OPERATION_ITEM_INDEX = 1; + private static final int OPERATION_QUANTITY_INDEX = 2; + private static final String CSV_COLUMN_NAMES_PATTERN = "type,fruit,quantity"; + + @Override + public List listOperationsFromCsv(List csvOperationsList) { + List operationsList = new ArrayList<>(); + int startLine = 0; + String firstLine = csvOperationsList.get(0); + if (firstLine.contains(CSV_COLUMN_NAMES_PATTERN)) { + startLine = 1; + } + for (int i = startLine; i < csvOperationsList.size(); i++) { + String csvOperation = csvOperationsList.get(i); + GoodsOperation operation = convertToOperationFromCsv(csvOperation); + operationsList.add(operation); + } + return operationsList; + } + + @Override + public GoodsOperation convertToOperationFromCsv(String operation) { + String [] line = operation.split(LINE_DIVIDER); + GoodsOperation.TransactionType type = GoodsOperation.TransactionType + .getByCode(line[OPERATION_TYPE_INDEX]); + String item = line[OPERATION_ITEM_INDEX]; + int quantity = Integer.parseInt(line[OPERATION_QUANTITY_INDEX]); + return new GoodsOperation(type, item, quantity); + } +} diff --git a/src/main/java/core/basesyntax/service/imp/FileReadServiceImp.java b/src/main/java/core/basesyntax/service/imp/FileReadServiceImp.java new file mode 100644 index 0000000000..ab215c4f8a --- /dev/null +++ b/src/main/java/core/basesyntax/service/imp/FileReadServiceImp.java @@ -0,0 +1,27 @@ +package core.basesyntax.service.imp; + +import core.basesyntax.service.FileReadService; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class FileReadServiceImp implements FileReadService { + @Override + public List readFilesLines(String path) { + File sourseFile = new File(path); + List filesLines = new ArrayList<>(); + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(sourseFile))) { + String line = bufferedReader.readLine(); + while (line != null) { + filesLines.add(line); + line = bufferedReader.readLine(); + } + } catch (IOException e) { + throw new RuntimeException("Can't read file " + sourseFile, e); + } + return filesLines; + } +} diff --git a/src/main/java/core/basesyntax/service/imp/FileWriteServiceImp.java b/src/main/java/core/basesyntax/service/imp/FileWriteServiceImp.java new file mode 100644 index 0000000000..4f51fae346 --- /dev/null +++ b/src/main/java/core/basesyntax/service/imp/FileWriteServiceImp.java @@ -0,0 +1,29 @@ +package core.basesyntax.service.imp; + +import core.basesyntax.service.FileWriteService; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.List; + +public class FileWriteServiceImp implements FileWriteService { + @Override + public void writeCsvToFile(List text, String path) { + checkValidText(text); + File file = new File(path); + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + for (String str : text) { + bufferedWriter.write(str); + } + } catch (IOException e) { + throw new RuntimeException("Can't write file" + path, e); + } + } + + private void checkValidText(List text) { + if (text == null) { + throw new NullPointerException("Can't write null data to file"); + } + } +} diff --git a/src/main/java/core/basesyntax/service/imp/Reporter.java b/src/main/java/core/basesyntax/service/imp/Reporter.java new file mode 100644 index 0000000000..72b4e7a449 --- /dev/null +++ b/src/main/java/core/basesyntax/service/imp/Reporter.java @@ -0,0 +1,35 @@ +package core.basesyntax.service.imp; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.service.ReportService; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class Reporter implements ReportService { + private static final String REPORT_HEAD = "fruit,quantity"; + private static final String SEPARATE_SYMBOL = ","; + private static final String LINE_SEPARATOR = System.lineSeparator(); + private final StorageDao storageDao; + + public Reporter(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public List getGoodsStockCsv() { + Set> goodsStock = storageDao.getStock().entrySet(); + List report = new ArrayList<>(); + report.add(REPORT_HEAD + LINE_SEPARATOR); + for (Map.Entry stock : goodsStock) { + StringBuilder line = new StringBuilder() + .append(stock.getKey()) + .append(SEPARATE_SYMBOL) + .append(stock.getValue()) + .append(LINE_SEPARATOR); + report.add(line.toString()); + } + return report; + } +} diff --git a/src/main/java/core/basesyntax/strategy/OperationHandler.java b/src/main/java/core/basesyntax/strategy/OperationHandler.java new file mode 100644 index 0000000000..d4aafc2c7a --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationHandler.java @@ -0,0 +1,7 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.GoodsOperation; + +public interface OperationHandler { + void handleOperation(GoodsOperation operation); +} diff --git a/src/main/java/core/basesyntax/strategy/OperationsStrategy.java b/src/main/java/core/basesyntax/strategy/OperationsStrategy.java new file mode 100644 index 0000000000..bdd9b7e426 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationsStrategy.java @@ -0,0 +1,16 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.GoodsOperation; +import java.util.Map; + +public class OperationsStrategy { + private final Map strategies; + + public OperationsStrategy(Map strategies) { + this.strategies = strategies; + } + + public void handleOperation(GoodsOperation operation) { + strategies.get(operation.getTransactionType()).handleOperation(operation); + } +} diff --git a/src/main/java/core/basesyntax/strategy/handlers/BalanceOperationHandler.java b/src/main/java/core/basesyntax/strategy/handlers/BalanceOperationHandler.java new file mode 100644 index 0000000000..86b05de05c --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/handlers/BalanceOperationHandler.java @@ -0,0 +1,27 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.strategy.OperationHandler; + +public class BalanceOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public BalanceOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void handleOperation(GoodsOperation operation) { + checkValidItem(operation); + String goodsName = operation.getItem(); + Integer balance = operation.getQuantity(); + storageDao.setQuantityGoods(goodsName, balance); + } + + private void checkValidItem(GoodsOperation operation) { + if (operation.getItem() == null) { + throw new RuntimeException("Goods name can't be null in transaction: " + operation); + } + } +} diff --git a/src/main/java/core/basesyntax/strategy/handlers/PurchaseOperationHandler.java b/src/main/java/core/basesyntax/strategy/handlers/PurchaseOperationHandler.java new file mode 100644 index 0000000000..48307db15a --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/handlers/PurchaseOperationHandler.java @@ -0,0 +1,36 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.strategy.OperationHandler; + +public class PurchaseOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public PurchaseOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void handleOperation(GoodsOperation operation) { + checkValidItem(operation); + String goodsName = operation.getItem(); + Integer itemStock = storageDao.getQuantityGoods(goodsName); + int operationQuantity = operation.getQuantity(); + checkGoodsStock(itemStock, operationQuantity); + storageDao.setQuantityGoods(goodsName, itemStock - operationQuantity); + } + + private void checkValidItem(GoodsOperation operation) { + if (operation.getItem() == null) { + throw new RuntimeException("Goods name can't be null in transaction: " + operation); + } + } + + private void checkGoodsStock(int itemStock, int operationQuantity) { + if (itemStock < operationQuantity) { + throw new RuntimeException( + "Quantity of purchase operation can't be more than stock of goods"); + } + } +} diff --git a/src/main/java/core/basesyntax/strategy/handlers/ReturnOperationHandler.java b/src/main/java/core/basesyntax/strategy/handlers/ReturnOperationHandler.java new file mode 100644 index 0000000000..541ecab12b --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/handlers/ReturnOperationHandler.java @@ -0,0 +1,31 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.strategy.OperationHandler; + +public class ReturnOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public ReturnOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void handleOperation(GoodsOperation operation) { + checkValidItem(operation); + String goodsName = operation.getItem(); + int newQuantity = operation.getQuantity(); + Integer itemStock = storageDao.getQuantityGoods(goodsName); + if (itemStock != null) { + newQuantity += itemStock; + } + storageDao.setQuantityGoods(goodsName, newQuantity); + } + + private void checkValidItem(GoodsOperation operation) { + if (operation.getItem() == null) { + throw new RuntimeException("Goods name can't be null in transaction: " + operation); + } + } +} diff --git a/src/main/java/core/basesyntax/strategy/handlers/SupplyOperationHandler.java b/src/main/java/core/basesyntax/strategy/handlers/SupplyOperationHandler.java new file mode 100644 index 0000000000..b09ca56f4d --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/handlers/SupplyOperationHandler.java @@ -0,0 +1,31 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.strategy.OperationHandler; + +public class SupplyOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public SupplyOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void handleOperation(GoodsOperation operation) { + checkValidItem(operation); + String goodsName = operation.getItem(); + int newQuantity = operation.getQuantity(); + Integer itemStock = storageDao.getQuantityGoods(goodsName); + if (itemStock != null) { + newQuantity += itemStock; + } + storageDao.setQuantityGoods(goodsName, newQuantity); + } + + private void checkValidItem(GoodsOperation operation) { + if (operation.getItem() == null) { + throw new RuntimeException("Goods name can't be null in transaction: " + operation); + } + } +} diff --git a/src/main/resources/ConsumerFile.txt b/src/main/resources/ConsumerFile.txt new file mode 100644 index 0000000000..6158e4419c --- /dev/null +++ b/src/main/resources/ConsumerFile.txt @@ -0,0 +1,3 @@ +fruit,quantity +banana,152 +apple,90 diff --git a/src/main/resources/SourceFile.txt b/src/main/resources/SourceFile.txt new file mode 100644 index 0000000000..c771f259d3 --- /dev/null +++ b/src/main/resources/SourceFile.txt @@ -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/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/service/CsvParseServiceTest.java b/src/test/java/core/basesyntax/service/CsvParseServiceTest.java new file mode 100644 index 0000000000..d9ddd75690 --- /dev/null +++ b/src/test/java/core/basesyntax/service/CsvParseServiceTest.java @@ -0,0 +1,42 @@ +package core.basesyntax.service; + +import core.basesyntax.model.GoodsOperation; +import core.basesyntax.service.imp.CsvParser; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class CsvParseServiceTest { + private static final String OPERATION_BALANCE_BANANA = "b,banana,20"; + private static final String OPERATION_BALANCE_APPLE = "b,apple,100"; + private static final String BANANA = "banana"; + private static final String APPLE = "apple"; + + private static CsvParseService csvParseService; + + @BeforeAll + static void beforeAll() { + csvParseService = new CsvParser(); + } + + @Test + void listOperationsFromCsv_validText_ok() { + List inputList = List.of(OPERATION_BALANCE_BANANA, OPERATION_BALANCE_APPLE); + List expected = List.of( + new GoodsOperation(GoodsOperation.TransactionType.BALANCE, BANANA, 20), + new GoodsOperation(GoodsOperation.TransactionType.BALANCE, APPLE, 100)); + List actual = csvParseService.listOperationsFromCsv(inputList); + Assertions.assertIterableEquals(expected, actual); + } + + @Test + void convertToOperationFromCsv_validText_ok() { + GoodsOperation expected = new GoodsOperation( + GoodsOperation.TransactionType.BALANCE, + BANANA, + 20); + GoodsOperation actual = csvParseService.convertToOperationFromCsv(OPERATION_BALANCE_BANANA); + Assertions.assertEquals(expected, actual); + } +} diff --git a/src/test/java/core/basesyntax/service/FileReadServiceTest.java b/src/test/java/core/basesyntax/service/FileReadServiceTest.java new file mode 100644 index 0000000000..1e3759741b --- /dev/null +++ b/src/test/java/core/basesyntax/service/FileReadServiceTest.java @@ -0,0 +1,60 @@ +package core.basesyntax.service; + +import core.basesyntax.service.imp.FileReadServiceImp; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class FileReadServiceTest { + private static final String PATH_SOURCE_FILE = "TestSourceFile.csv"; + private static final String OPERATION_BALANCE_BANANA = "b,banana,20"; + private static final String OPERATION_BALANCE_APPLE = "b,apple,100"; + private static final String OPERATION_SUPPLY_APPLE = "s,banana,100"; + private static final String INVALID_OPERATION_APPLE = "p,apple,20"; + + private static FileReadService fileReadService; + private static File file; + + @AfterAll + static void afterAll() { + try { + Files.deleteIfExists(Path.of(PATH_SOURCE_FILE)); + } catch (IOException e) { + throw new RuntimeException("Can't correctly clear result files after test ", e); + } + } + + @BeforeAll + static void beforeAll() { + fileReadService = new FileReadServiceImp(); + String testFileText = OPERATION_BALANCE_BANANA + + System.lineSeparator() + OPERATION_BALANCE_APPLE + + System.lineSeparator() + OPERATION_SUPPLY_APPLE + + System.lineSeparator() + INVALID_OPERATION_APPLE; + file = new File(PATH_SOURCE_FILE); + try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file))) { + bufferedWriter.write(testFileText); + } catch (IOException e) { + throw new RuntimeException("Can't create file: " + PATH_SOURCE_FILE, e); + } + } + + @Test + void readFilesLines_validFile_Ok() { + List expected = List.of( + OPERATION_BALANCE_BANANA, + OPERATION_BALANCE_APPLE, + OPERATION_SUPPLY_APPLE, + INVALID_OPERATION_APPLE); + List actual = fileReadService.readFilesLines(PATH_SOURCE_FILE); + Assertions.assertEquals(expected, actual); + } +} diff --git a/src/test/java/core/basesyntax/service/FileWriteServiceTest.java b/src/test/java/core/basesyntax/service/FileWriteServiceTest.java new file mode 100644 index 0000000000..1be1170c80 --- /dev/null +++ b/src/test/java/core/basesyntax/service/FileWriteServiceTest.java @@ -0,0 +1,87 @@ +package core.basesyntax.service; + +import core.basesyntax.service.imp.FileWriteServiceImp; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class FileWriteServiceTest { + private static final String PATH_CONSUMER_FILE = "TestConsumerFile.csv"; + private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String REPORT_HEAD = "fruit,quantity"; + private static final String STOCK_BANANA_QUANTITY = "banana,50"; + private static final String STOCK_APPLE_QUANTITY = "apple,100"; + + private static FileWriteService fileWriteService; + private static File file; + + @BeforeAll + static void beforeAll() { + fileWriteService = new FileWriteServiceImp(); + file = new File(PATH_CONSUMER_FILE); + } + + @AfterAll + static void afterAll() { + try { + Files.deleteIfExists(Path.of(PATH_CONSUMER_FILE)); + } catch (IOException e) { + throw new RuntimeException("Can't correctly clear result files after test ", e); + } + } + + @Test + void writeCsvToFile_allValid_ok() { + List inputData = List.of( + REPORT_HEAD + LINE_SEPARATOR, + STOCK_BANANA_QUANTITY + LINE_SEPARATOR, + STOCK_APPLE_QUANTITY + LINE_SEPARATOR); + List expectedList = List.of(REPORT_HEAD, + STOCK_BANANA_QUANTITY, + STOCK_APPLE_QUANTITY); + fileWriteService.writeCsvToFile(inputData, PATH_CONSUMER_FILE); + List actualList = readFile(PATH_CONSUMER_FILE); + Assertions. assertIterableEquals(expectedList, actualList); + } + + @Test + void writeCsvToFile_emptyData_ok() { + List inputData = List.of(REPORT_HEAD); + List expectedList = List.of(REPORT_HEAD); + fileWriteService.writeCsvToFile(inputData, PATH_CONSUMER_FILE); + List actualList = readFile(PATH_CONSUMER_FILE); + Assertions. assertIterableEquals(expectedList, actualList); + + } + + @Test + void writeCsvToFile_nullData_notOk() { + Assertions.assertThrows(NullPointerException.class, + () -> fileWriteService.writeCsvToFile(null, PATH_CONSUMER_FILE), + "Method should throw NullPointerException with null input text"); + } + + private List readFile(String path) { + List filesLines = new ArrayList<>(); + try (BufferedReader bufferedReader = new BufferedReader( + new FileReader(path))) { + String line = bufferedReader.readLine(); + while (line != null) { + filesLines.add(line); + line = bufferedReader.readLine(); + } + } catch (IOException e) { + throw new RuntimeException("Can't read file " + file, e); + } + return filesLines; + } +} diff --git a/src/test/java/core/basesyntax/service/ReportServiceTest.java b/src/test/java/core/basesyntax/service/ReportServiceTest.java new file mode 100644 index 0000000000..b6bad63ce0 --- /dev/null +++ b/src/test/java/core/basesyntax/service/ReportServiceTest.java @@ -0,0 +1,45 @@ +package core.basesyntax.service; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.service.imp.Reporter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ReportServiceTest { + private static final String LINE_SEPARATOR = System.lineSeparator(); + private static final String REPORT_HEAD = "fruit,quantity"; + + private static ReportService reportService; + private static StorageDao storageDao; + private static Map storage; + + @BeforeAll + static void beforeAll() { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + reportService = new Reporter(storageDao); + } + + @AfterEach + void tearDown() { + storage.clear(); + } + + @Test + void getGoodsStockCsv_validData_ok() { + storage.put("banana", 50); + storage.put("apple", 100); + List expectedsList = List.of( + REPORT_HEAD + LINE_SEPARATOR, + "banana,50" + LINE_SEPARATOR, + "apple,100" + LINE_SEPARATOR); + List actualList = reportService.getGoodsStockCsv(); + Assertions. assertIterableEquals(expectedsList, actualList); + } +} diff --git a/src/test/java/core/basesyntax/strategy/handlers/BalanceOperationHandlerTest.java b/src/test/java/core/basesyntax/strategy/handlers/BalanceOperationHandlerTest.java new file mode 100644 index 0000000000..a70efd7890 --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/handlers/BalanceOperationHandlerTest.java @@ -0,0 +1,58 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.model.GoodsOperation; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class BalanceOperationHandlerTest { + private static final String BANANA = "banana"; + + private static Map storage; + private static StorageDao storageDao; + private static BalanceOperationHandler balanceOperationHandler; + private static GoodsOperation balanceOperation; + + @BeforeAll + static void beforeAll() { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + balanceOperationHandler = new BalanceOperationHandler(storageDao); + balanceOperation = new GoodsOperation(GoodsOperation.TransactionType.BALANCE, + BANANA, 50); + } + + @AfterEach + void tearDown() { + storage.clear(); + } + + @Test + void handleOperation_validOperations_ok() { + balanceOperationHandler.handleOperation(balanceOperation); + Integer actual = storage.get(balanceOperation.getItem()); + Integer expected = balanceOperation.getQuantity(); + Assertions.assertEquals(expected, actual, + String.format("Expected quantity of %s not equals actual", + balanceOperation.getItem())); + } + + @Test + void handleOperation_nullItemName_notOk() { + balanceOperation = new GoodsOperation(balanceOperation.getTransactionType(), + null, + balanceOperation.getQuantity()); + String expectedMessage = "can't be null"; + Exception exception = Assertions.assertThrows(RuntimeException.class, () -> { + balanceOperationHandler.handleOperation(balanceOperation); + }); + String actualMessage = exception.getMessage(); + Assertions.assertTrue(actualMessage.contains(expectedMessage), + "Exception message must contain string: " + expectedMessage); + } +} diff --git a/src/test/java/core/basesyntax/strategy/handlers/PurchaseOperationHandlerTest.java b/src/test/java/core/basesyntax/strategy/handlers/PurchaseOperationHandlerTest.java new file mode 100644 index 0000000000..320459f688 --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/handlers/PurchaseOperationHandlerTest.java @@ -0,0 +1,68 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.model.GoodsOperation; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class PurchaseOperationHandlerTest { + private static final String BANANA = "banana"; + private static Map storage; + private static StorageDao storageDao; + private static PurchaseOperationHandler purchaseOperationHandler; + private static GoodsOperation purchaseOperation; + + @BeforeAll + static void beforeAll() { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + purchaseOperationHandler = new PurchaseOperationHandler(storageDao); + purchaseOperation = new GoodsOperation(GoodsOperation.TransactionType.PURCHASE, + BANANA, 24); + } + + @AfterEach + void tearDown() { + storage.clear(); + } + + @Test + void handleOperation_validOperations_ok() { + int stocksQuantity = 73; + storage.put(BANANA, stocksQuantity); + purchaseOperationHandler.handleOperation(purchaseOperation); + Integer actual = storage.get(purchaseOperation.getItem()); + Integer expected = stocksQuantity - purchaseOperation.getQuantity(); + Assertions.assertEquals(expected, actual, + String.format("Expected quantity of %s not equals actual", + purchaseOperation.getItem())); + } + + @Test + void handleOperation_nullItemName_notOk() { + purchaseOperation = new GoodsOperation(purchaseOperation.getTransactionType(), + null, + purchaseOperation.getQuantity()); + String expectedMessage = "can't be null"; + Exception exception = Assertions.assertThrows(RuntimeException.class, () -> { + purchaseOperationHandler.handleOperation(purchaseOperation); + }); + String actualMessage = exception.getMessage(); + Assertions.assertTrue(actualMessage.contains(expectedMessage), + "Exception message must contain string: " + expectedMessage); + } + + @Test + void handleOperation_stocksLack_notOk() { + int stocksQuantity = 1; + storage.put("banana", stocksQuantity); + Assertions.assertThrows(RuntimeException.class, + () -> purchaseOperationHandler.handleOperation(purchaseOperation), + "Quantity of purchase operation can't be more than stock of goods"); + } +} diff --git a/src/test/java/core/basesyntax/strategy/handlers/ReturnOperationHandlerTest.java b/src/test/java/core/basesyntax/strategy/handlers/ReturnOperationHandlerTest.java new file mode 100644 index 0000000000..5525a946a0 --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/handlers/ReturnOperationHandlerTest.java @@ -0,0 +1,57 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.model.GoodsOperation; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ReturnOperationHandlerTest { + private static final String BANANA = "banana"; + private static Map storage; + private static StorageDao storageDao; + private static ReturnOperationHandler returnOperationHandler; + private static GoodsOperation returnOperation; + + @BeforeAll + static void beforeAll() { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + returnOperationHandler = new ReturnOperationHandler(storageDao); + returnOperation = new GoodsOperation(GoodsOperation.TransactionType.RETURN, + BANANA, 50); + } + + @AfterEach + void tearDown() { + storage.clear(); + } + + @Test + void handleOperation_validOperations_ok() { + returnOperationHandler.handleOperation(returnOperation); + Integer actual = storage.get(returnOperation.getItem()); + Integer expected = returnOperation.getQuantity(); + Assertions.assertEquals(expected, actual, + String.format("Expected quantity of %s not equals actual", + returnOperation.getItem())); + } + + @Test + void handleOperation_nullItemName_notOk() { + returnOperation = new GoodsOperation(returnOperation.getTransactionType(), + null, + returnOperation.getQuantity()); + String expectedMessage = "can't be null"; + Exception exception = Assertions.assertThrows(RuntimeException.class, () -> { + returnOperationHandler.handleOperation(returnOperation); + }); + String actualMessage = exception.getMessage(); + Assertions.assertTrue(actualMessage.contains(expectedMessage), + "Exception message must contain string: " + expectedMessage); + } +} diff --git a/src/test/java/core/basesyntax/strategy/handlers/SupplyOperationHandlerTest.java b/src/test/java/core/basesyntax/strategy/handlers/SupplyOperationHandlerTest.java new file mode 100644 index 0000000000..ff9dfa7437 --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/handlers/SupplyOperationHandlerTest.java @@ -0,0 +1,57 @@ +package core.basesyntax.strategy.handlers; + +import core.basesyntax.db.dao.StorageDao; +import core.basesyntax.db.dao.StorageDaoImp; +import core.basesyntax.model.GoodsOperation; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class SupplyOperationHandlerTest { + private static final String BANANA = "banana"; + private static Map storage; + private static StorageDao storageDao; + private static SupplyOperationHandler supplyOperationHandler; + private static GoodsOperation supplyOperation; + + @BeforeAll + static void beforeAll() { + storage = new HashMap<>(); + storageDao = new StorageDaoImp(storage); + supplyOperationHandler = new SupplyOperationHandler(storageDao); + supplyOperation = new GoodsOperation(GoodsOperation.TransactionType.SUPPLY, + BANANA, 50); + } + + @AfterEach + void tearDown() { + storage.clear(); + } + + @Test + void handleOperation_validOperations_ok() { + supplyOperationHandler.handleOperation(supplyOperation); + Integer actual = storage.get(supplyOperation.getItem()); + Integer expected = supplyOperation.getQuantity(); + Assertions.assertEquals(expected, actual, + String.format("Expected quantity of %s not equals actual", + supplyOperation.getItem())); + } + + @Test + void handleOperation_nullItemName_notOk() { + supplyOperation = new GoodsOperation(supplyOperation.getTransactionType(), + null, + supplyOperation.getQuantity()); + String expectedMessage = "can't be null"; + Exception exception = Assertions.assertThrows(RuntimeException.class, () -> { + supplyOperationHandler.handleOperation(supplyOperation); + }); + String actualMessage = exception.getMessage(); + Assertions.assertTrue(actualMessage.contains(expectedMessage), + "Exception message must contain string: " + expectedMessage); + } +}