diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..7c87609586 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 6366460f0a..50e3bd00ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .idea/* *.iml target/* +.DS_Store + diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000..18fc9d1e04 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/main/.DS_Store b/src/main/.DS_Store new file mode 100644 index 0000000000..623ded4db9 Binary files /dev/null and b/src/main/.DS_Store differ diff --git a/src/main/java/.DS_Store b/src/main/java/.DS_Store new file mode 100644 index 0000000000..44a62117e4 Binary files /dev/null and b/src/main/java/.DS_Store differ diff --git a/src/main/java/core/.DS_Store b/src/main/java/core/.DS_Store new file mode 100644 index 0000000000..213115cdaf Binary files /dev/null and b/src/main/java/core/.DS_Store differ diff --git a/src/main/java/core/basesyntax/.DS_Store b/src/main/java/core/basesyntax/.DS_Store new file mode 100644 index 0000000000..104ccac539 Binary files /dev/null and b/src/main/java/core/basesyntax/.DS_Store differ 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..588cf3c588 --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,49 @@ +package core.basesyntax; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.model.Operation; +import core.basesyntax.service.DataProcessing; +import core.basesyntax.service.DataReader; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.service.ReportCreator; +import core.basesyntax.service.Writer; +import core.basesyntax.service.handler.impl.BalanceOperationHandler; +import core.basesyntax.service.handler.impl.PurchaseOperationHandler; +import core.basesyntax.service.handler.impl.ReturnOperationHandler; +import core.basesyntax.service.handler.impl.SupplyOperationHandler; +import core.basesyntax.service.impl.CsvWriter; +import core.basesyntax.service.impl.DataProcessingImpl; +import core.basesyntax.service.impl.DataReaderFromCsv; +import core.basesyntax.service.impl.FruitShopServiceImpl; +import core.basesyntax.service.impl.ReportCreatorImpl; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.impl.OperationStrategyImpl; +import java.util.HashMap; +import java.util.Map; + +public class Main { + private static final String FILE_FROM = "src/main/resources/data.csv"; + private static final String FILE_TO = "src/main/resources/report.csv"; + + public static void main(String[] args) { + StorageDao storageDao = new StorageDaoImpl(); + Map operationHandlerMap = new HashMap<>(); + operationHandlerMap.put(Operation.BALANCE, + new BalanceOperationHandler(storageDao)); + operationHandlerMap.put(Operation.SUPPLY, + new SupplyOperationHandler(storageDao)); + operationHandlerMap.put(Operation.PURCHASE, + new PurchaseOperationHandler(storageDao)); + operationHandlerMap.put(Operation.RETURN, + new ReturnOperationHandler(storageDao)); + OperationStrategy operationStrategy = new OperationStrategyImpl(operationHandlerMap); + DataReader dataReader = new DataReaderFromCsv(); + DataProcessing dataProcessing = new DataProcessingImpl(operationStrategy); + ReportCreator reportCreator = new ReportCreatorImpl(storageDao); + Writer writer = new CsvWriter(); + FruitShopServiceImpl fruitShopService = new FruitShopServiceImpl(dataReader, + dataProcessing, reportCreator, writer); + fruitShopService.createDailyReport(FILE_FROM, FILE_TO); + } +} diff --git a/src/main/java/core/basesyntax/dao/StorageDao.java b/src/main/java/core/basesyntax/dao/StorageDao.java new file mode 100644 index 0000000000..5961e5fbc6 --- /dev/null +++ b/src/main/java/core/basesyntax/dao/StorageDao.java @@ -0,0 +1,14 @@ +package core.basesyntax.dao; + +import core.basesyntax.model.Fruit; +import java.util.Map; + +public interface StorageDao { + void add(Fruit fruit, Integer amount); + + Map.Entry get(String name); + + boolean isInStorage(String name); + + Map getAll(); +} diff --git a/src/main/java/core/basesyntax/dao/StorageDaoImpl.java b/src/main/java/core/basesyntax/dao/StorageDaoImpl.java new file mode 100644 index 0000000000..20eac3521c --- /dev/null +++ b/src/main/java/core/basesyntax/dao/StorageDaoImpl.java @@ -0,0 +1,32 @@ +package core.basesyntax.dao; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import java.util.HashMap; +import java.util.Map; + +public class StorageDaoImpl implements StorageDao { + @Override + public void add(Fruit fruit, Integer amount) { + Storage.fruits.put(fruit, amount); + } + + @Override + public Map.Entry get(String name) { + for (Map.Entry entry : Storage.fruits.entrySet()) { + if (entry.getKey().getName().equals(name)) { + return entry; + } + } + return null; + } + + public boolean isInStorage(String name) { + return get(name) != null; + } + + @Override + public Map getAll() { + return new HashMap<>(Storage.fruits); + } +} diff --git a/src/main/java/core/basesyntax/db/Storage.java b/src/main/java/core/basesyntax/db/Storage.java new file mode 100644 index 0000000000..94c4799415 --- /dev/null +++ b/src/main/java/core/basesyntax/db/Storage.java @@ -0,0 +1,9 @@ +package core.basesyntax.db; + +import core.basesyntax.model.Fruit; +import java.util.HashMap; +import java.util.Map; + +public class Storage { + public static final Map fruits = new HashMap<>(); +} diff --git a/src/main/java/core/basesyntax/model/Fruit.java b/src/main/java/core/basesyntax/model/Fruit.java new file mode 100644 index 0000000000..1ccbedec9a --- /dev/null +++ b/src/main/java/core/basesyntax/model/Fruit.java @@ -0,0 +1,41 @@ +package core.basesyntax.model; + +import java.util.Objects; + +public class Fruit { + private String name; + + public Fruit(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Fruit fruit = (Fruit) o; + return Objects.equals(name, fruit.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return "Fruit{" + "name='" + name + '\'' + '}'; + } +} 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..b04c9cf1b6 --- /dev/null +++ b/src/main/java/core/basesyntax/model/FruitTransaction.java @@ -0,0 +1,31 @@ +package core.basesyntax.model; + +public class FruitTransaction { + private Operation operation; + private String fruitName; + private int amount; + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } + + public String getFruitName() { + return fruitName; + } + + public void setFruitName(String fruit) { + this.fruitName = fruit; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } +} diff --git a/src/main/java/core/basesyntax/model/Operation.java b/src/main/java/core/basesyntax/model/Operation.java new file mode 100644 index 0000000000..9e6002a65f --- /dev/null +++ b/src/main/java/core/basesyntax/model/Operation.java @@ -0,0 +1,28 @@ +package core.basesyntax.model; + +import java.util.Arrays; + +public enum Operation { + BALANCE("b"), + SUPPLY("s"), + PURCHASE("p"), + RETURN("r"); + + private String code; + + Operation(String code) { + this.code = code; + } + + public String getCodeOfOperation() { + return code; + } + + public static Operation getOperationOf(String letter) { + return Arrays.stream(Operation.values()) + .filter(operation -> operation.getCodeOfOperation().equals(letter)) + .findFirst() + .orElseThrow(() -> new RuntimeException("There is no such operation by letter " + + "'" + letter + "'")); + } +} diff --git a/src/main/java/core/basesyntax/service/DataProcessing.java b/src/main/java/core/basesyntax/service/DataProcessing.java new file mode 100644 index 0000000000..1375df05ff --- /dev/null +++ b/src/main/java/core/basesyntax/service/DataProcessing.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface DataProcessing { + void processTransaction(List data); +} diff --git a/src/main/java/core/basesyntax/service/DataReader.java b/src/main/java/core/basesyntax/service/DataReader.java new file mode 100644 index 0000000000..e09492732d --- /dev/null +++ b/src/main/java/core/basesyntax/service/DataReader.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface DataReader { + List readData(String file); + +} 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..8898a2d365 --- /dev/null +++ b/src/main/java/core/basesyntax/service/OperationHandler.java @@ -0,0 +1,16 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; + +public interface OperationHandler { + int MIN_AMOUNT = 0; + + void updateStorage(FruitTransaction transaction); + + default void validAmount(FruitTransaction transaction) { + if (transaction.getAmount() < MIN_AMOUNT) { + throw new RuntimeException("OPERATION " + transaction.getOperation() + + "! Amount is less then zero!!!"); + } + } +} diff --git a/src/main/java/core/basesyntax/service/ReportCreator.java b/src/main/java/core/basesyntax/service/ReportCreator.java new file mode 100644 index 0000000000..54e05395c7 --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportCreator.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface ReportCreator { + String createReport(); +} diff --git a/src/main/java/core/basesyntax/service/Writer.java b/src/main/java/core/basesyntax/service/Writer.java new file mode 100644 index 0000000000..2c12c7dfef --- /dev/null +++ b/src/main/java/core/basesyntax/service/Writer.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface Writer { + void writeReportToFile(String report, String toFile); +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java new file mode 100644 index 0000000000..3bbf50c43b --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java @@ -0,0 +1,23 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; + +public class BalanceOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public BalanceOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + String fruitName = transaction.getFruitName(); + if (!storageDao.isInStorage(fruitName)) { + storageDao.add(new Fruit(fruitName), transaction.getAmount()); + } + } +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java new file mode 100644 index 0000000000..74a7510e0b --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java @@ -0,0 +1,36 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class PurchaseOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public PurchaseOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmountOfFruit(transaction); + Map.Entry fruitAndAmount = storageDao.get(transaction.getFruitName()); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount - fruitAmountFromTransaction); + } + + private void validAmountOfFruit(FruitTransaction transaction) { + validAmount(transaction); + String fruitName = transaction.getFruitName(); + if (!storageDao.isInStorage(fruitName)) { + throw new RuntimeException("There is no such fruit!!!"); + } + if (storageDao.get(fruitName).getValue() < transaction.getAmount()) { + throw new RuntimeException("Amount of " + transaction.getFruitName() + + " isn't enough!!!"); + } + } +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java new file mode 100644 index 0000000000..6aa57d9d07 --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java @@ -0,0 +1,29 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class ReturnOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public ReturnOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + String fruitName = transaction.getFruitName(); + if (!storageDao.isInStorage(fruitName)) { + storageDao.add(new Fruit(fruitName), transaction.getAmount()); + } else { + Map.Entry fruitAndAmount = storageDao.get(fruitName); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount + fruitAmountFromTransaction); + } + } +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java new file mode 100644 index 0000000000..75e7f5084e --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java @@ -0,0 +1,29 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class SupplyOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public SupplyOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + String fruitName = transaction.getFruitName(); + if (!storageDao.isInStorage(fruitName)) { + storageDao.add(new Fruit(fruitName), transaction.getAmount()); + } else { + Map.Entry fruitAndAmount = storageDao.get(fruitName); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount + fruitAmountFromTransaction); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/CsvWriter.java b/src/main/java/core/basesyntax/service/impl/CsvWriter.java new file mode 100644 index 0000000000..f6d3c98dc7 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/CsvWriter.java @@ -0,0 +1,19 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.Writer; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CsvWriter implements Writer { + private static final String EXCEPTION_MESSAGE = "Can't write data to file: "; + + @Override + public void writeReportToFile(String report, String toFile) { + try { + Files.write(Path.of(toFile), report.getBytes()); + } catch (IOException e) { + throw new RuntimeException(EXCEPTION_MESSAGE + toFile); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java b/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java new file mode 100644 index 0000000000..c6d5e96103 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java @@ -0,0 +1,48 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.DataProcessing; +import core.basesyntax.strategy.OperationStrategy; +import java.util.List; + +public class DataProcessingImpl implements DataProcessing { + private static final String SPLITERATOR = ","; + private static final int OPERATION_POSITION = 0; + private static final int FRUIT_NAME_POSITION = 1; + private static final int AMOUNT_OF_FRUIT_POSITION = 2; + private static final String DATA_NULL = "Data is null!!!"; + private final OperationStrategy operationStrategy; + + public DataProcessingImpl(OperationStrategy operationStrategy) { + this.operationStrategy = operationStrategy; + } + + @Override + public void processTransaction(List data) { + if (data == null) { + throw new RuntimeException(DATA_NULL); + } + List fruitTransactions = getFruitTransactions(data); + fruitTransactions + .forEach(t -> operationStrategy.getOperationHandler(t.getOperation()) + .updateStorage(t)); + } + + private List getFruitTransactions(List data) { + return data.stream() + .map(this::getTransactionFromRow) + .toList(); + } + + private FruitTransaction getTransactionFromRow(String line) { + FruitTransaction fruitTransaction = new FruitTransaction(); + String[] rowWithTransaction = line.split(SPLITERATOR); + fruitTransaction.setOperation(Operation.getOperationOf( + rowWithTransaction[OPERATION_POSITION].trim())); + fruitTransaction.setFruitName(rowWithTransaction[FRUIT_NAME_POSITION].trim()); + fruitTransaction.setAmount(Integer + .parseInt(rowWithTransaction[AMOUNT_OF_FRUIT_POSITION].trim())); + return fruitTransaction; + } +} diff --git a/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java b/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java new file mode 100644 index 0000000000..5ad8e24f0f --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java @@ -0,0 +1,23 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.DataReader; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.List; + +public class DataReaderFromCsv implements DataReader { + private static final int ROW_TO_SKIP = 1; + private static final String EXCEPTION_MESSAGE = "Can't read data from file: "; + + @Override + public List readData(String file) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + return reader.lines() + .skip(ROW_TO_SKIP) + .toList(); + } catch (IOException e) { + throw new RuntimeException(EXCEPTION_MESSAGE + file); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java b/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java new file mode 100644 index 0000000000..89b4cc5f89 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java @@ -0,0 +1,30 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.DataProcessing; +import core.basesyntax.service.DataReader; +import core.basesyntax.service.ReportCreator; +import core.basesyntax.service.Writer; +import java.util.List; + +public class FruitShopServiceImpl { + private final DataReader dataReader; + private final DataProcessing dataProcessing; + private final ReportCreator reportCreator; + private final Writer writer; + + public FruitShopServiceImpl(DataReader dataReader, DataProcessing dataProcessing, + ReportCreator reportCreator, Writer writer) { + this.dataReader = dataReader; + this.dataProcessing = dataProcessing; + this.reportCreator = reportCreator; + this.writer = writer; + } + + public void createDailyReport(String fromFile, String toFile) { + List dataFromFile = dataReader.readData(fromFile); + dataProcessing.processTransaction(dataFromFile); + String report = reportCreator.createReport(); + writer.writeReportToFile(report, toFile); + } + +} diff --git a/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java b/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java new file mode 100644 index 0000000000..903e5261bd --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java @@ -0,0 +1,25 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.service.ReportCreator; +import java.util.stream.Collectors; + +public class ReportCreatorImpl implements ReportCreator { + private static final String SEPARATOR = ","; + private static final String REPORT_HEADER = "fruit,quantity"; + private static final String JOINING_SUFFIX = ""; + private final StorageDao storageDao; + + public ReportCreatorImpl(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public String createReport() { + return storageDao.getAll().entrySet().stream() + .map(fruitAmountEntry -> fruitAmountEntry.getKey().getName() + + SEPARATOR + fruitAmountEntry.getValue()) + .collect(Collectors.joining(System.lineSeparator(), + REPORT_HEADER + System.lineSeparator(), JOINING_SUFFIX)); + } +} 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..b7b18caeab --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationStrategy.java @@ -0,0 +1,8 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; + +public interface OperationStrategy { + OperationHandler getOperationHandler(Operation operation); +} diff --git a/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java b/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java new file mode 100644 index 0000000000..6e92492868 --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java @@ -0,0 +1,24 @@ +package core.basesyntax.strategy.impl; + +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.strategy.OperationStrategy; +import java.util.Map; + +public class OperationStrategyImpl implements OperationStrategy { + private static final String MAP_IS_NULL = "Map with handlers is NULL!!!"; + private final Map operationHandlerMap; + + public OperationStrategyImpl(Map operationHandlerMap) { + this.operationHandlerMap = operationHandlerMap; + } + + @Override + public OperationHandler getOperationHandler(Operation operation) { + if (operationHandlerMap == null) { + throw new RuntimeException(MAP_IS_NULL); + } + return operationHandlerMap.get(operation); + } +} diff --git a/src/main/resources/data.csv b/src/main/resources/data.csv new file mode 100644 index 0000000000..c1e2881838 --- /dev/null +++ b/src/main/resources/data.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/report.csv b/src/main/resources/report.csv new file mode 100644 index 0000000000..d7ee69b6d1 --- /dev/null +++ b/src/main/resources/report.csv @@ -0,0 +1,3 @@ +fruit,quantity +banana,152 +apple,90 \ No newline at end of file diff --git a/src/test/.DS_Store b/src/test/.DS_Store new file mode 100644 index 0000000000..05ce5c9cac Binary files /dev/null and b/src/test/.DS_Store differ 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/StorageDaoImplTest.java b/src/test/java/core/basesyntax/dao/StorageDaoImplTest.java new file mode 100644 index 0000000000..7af008872a --- /dev/null +++ b/src/test/java/core/basesyntax/dao/StorageDaoImplTest.java @@ -0,0 +1,95 @@ +package core.basesyntax.dao; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class StorageDaoImplTest { + private static final Integer AMOUNT = 100; + private static final String FRUIT_NAME = "banana"; + private static final String NAME_OF_NOT_EXISTING_FRUIT = "grape"; + private static StorageDao storageDao; + private static Map expectedMap; + private Fruit fruit; + + @BeforeAll + static void beforeAll() { + storageDao = new StorageDaoImpl(); + expectedMap = new HashMap<>(); + } + + @BeforeEach + void setUp() { + fruit = new Fruit(FRUIT_NAME); + expectedMap.put(fruit, AMOUNT); + } + + @Test + void storageDao_add_isOk() { + storageDao.add(fruit, AMOUNT); + Map actualMap = Storage.fruits; + + assertEquals(expectedMap, actualMap); + } + + @Test + void storageDao_getExistingFruit_isOk() { + Storage.fruits.put(fruit, AMOUNT); + + Map.Entry actualEntry = storageDao.get(fruit.getName()); + Fruit actualFruit = actualEntry.getKey(); + Integer actualAmount = actualEntry.getValue(); + + assertEquals(fruit, actualFruit); + assertEquals(AMOUNT, actualAmount); + } + + @Test + void storageDao_getNullIfNotExist_isOk() { + Storage.fruits.put(fruit, AMOUNT); + + Map.Entry actualEntry = storageDao.get(NAME_OF_NOT_EXISTING_FRUIT); + + assertNull(actualEntry); + } + + @Test + void storageDao_getAll_isOk() { + Storage.fruits.put(fruit, AMOUNT); + + Map actualMap = storageDao.getAll(); + + assertEquals(expectedMap, actualMap); + } + + @Test + void storageDao_isInStorage_isOk() { + Storage.fruits.put(fruit, AMOUNT); + + boolean actual = storageDao.isInStorage(fruit.getName()); + + assertTrue(actual); + } + + @Test + void storageDao_isNotInStorage_isOk() { + boolean actual = storageDao.isInStorage(FRUIT_NAME); + + assertFalse(actual); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/handler/impl/BalanceOperationHandlerTest.java b/src/test/java/core/basesyntax/service/handler/impl/BalanceOperationHandlerTest.java new file mode 100644 index 0000000000..4fcda9bc81 --- /dev/null +++ b/src/test/java/core/basesyntax/service/handler/impl/BalanceOperationHandlerTest.java @@ -0,0 +1,80 @@ +package core.basesyntax.service.handler.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BalanceOperationHandlerTest { + private static final String FRUIT_NAME = "apple"; + private static final int FRUIT_AMOUNT = 50; + private static final int FRUIT_NEGATIVE_AMOUNT = -50; + private static OperationHandler operationHandler; + private static FruitTransaction transaction; + private static FruitTransaction transactionWithNegativeAmount; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + operationHandler = new BalanceOperationHandler(storageDao); + transaction = new FruitTransaction(); + transactionWithNegativeAmount = new FruitTransaction(); + } + + @BeforeEach + void setUp() { + transaction.setOperation(Operation.BALANCE); + transaction.setFruitName(FRUIT_NAME); + transaction.setAmount(FRUIT_AMOUNT); + transactionWithNegativeAmount.setOperation(Operation.BALANCE); + transactionWithNegativeAmount.setFruitName(FRUIT_NAME); + transactionWithNegativeAmount.setAmount(FRUIT_NEGATIVE_AMOUNT); + } + + @Test + void updateStorage_isOk() { + operationHandler.updateStorage(transaction); + Integer expectedFruitAmount = FRUIT_AMOUNT; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitInStorage_isOk() { + operationHandler.updateStorage(transaction); + operationHandler.updateStorage(transaction); + Integer expectedFruitAmount = FRUIT_AMOUNT; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitAmountIsNegative_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transactionWithNegativeAmount); + }, "If amount is negative it should throw RuntimeException!"); + + String expectedMessage = "Amount is less then zero!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/handler/impl/PurchaseOperationHandlerTest.java b/src/test/java/core/basesyntax/service/handler/impl/PurchaseOperationHandlerTest.java new file mode 100644 index 0000000000..69a302a370 --- /dev/null +++ b/src/test/java/core/basesyntax/service/handler/impl/PurchaseOperationHandlerTest.java @@ -0,0 +1,118 @@ +package core.basesyntax.service.handler.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class PurchaseOperationHandlerTest { + private static final String FRUIT_NAME = "banana"; + private static final int FRUIT_AMOUNT = 120; + private static final int FRUIT_NEGATIVE_AMOUNT = -50; + private static final int FRUIT_GREATER_AMOUNT = 140; + private static final int FRUIT_LESS_AMOUNT = 100; + private static OperationHandler operationHandler; + private static FruitTransaction transaction; + private static FruitTransaction transactionWithNegativeAmount; + private static FruitTransaction transactionWithGreaterAmount; + private static FruitTransaction transactionWithLessAmount; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + operationHandler = new PurchaseOperationHandler(storageDao); + transaction = new FruitTransaction(); + transactionWithNegativeAmount = new FruitTransaction(); + transactionWithGreaterAmount = new FruitTransaction(); + transactionWithLessAmount = new FruitTransaction(); + } + + @BeforeEach + void setUp() { + transaction.setOperation(Operation.PURCHASE); + transaction.setFruitName(FRUIT_NAME); + transaction.setAmount(FRUIT_AMOUNT); + transactionWithNegativeAmount.setOperation(Operation.PURCHASE); + transactionWithNegativeAmount.setFruitName(FRUIT_NAME); + transactionWithNegativeAmount.setAmount(FRUIT_NEGATIVE_AMOUNT); + transactionWithGreaterAmount.setOperation(Operation.PURCHASE); + transactionWithGreaterAmount.setFruitName(FRUIT_NAME); + transactionWithGreaterAmount.setAmount(FRUIT_GREATER_AMOUNT); + transactionWithLessAmount.setOperation(Operation.PURCHASE); + transactionWithLessAmount.setFruitName(FRUIT_NAME); + transactionWithLessAmount.setAmount(FRUIT_LESS_AMOUNT); + } + + @Test + void updateStorage_emptyStorage_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transaction); + }, "If storage does not have such fruit it should throw Runtime Exception"); + + String expectedMessage = "There is no such fruit!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + + } + + @Test + void updateStorage_fruitInStorage_isOk() { + Storage.fruits.put(new Fruit(FRUIT_NAME), FRUIT_AMOUNT); + + operationHandler.updateStorage(transaction); + Integer expectedFruitAmount = FRUIT_AMOUNT - transaction.getAmount(); + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + + Storage.fruits.put(new Fruit(FRUIT_NAME), FRUIT_AMOUNT); + + operationHandler.updateStorage(transactionWithLessAmount); + Integer expectedFruitAmount2 = FRUIT_AMOUNT - transactionWithLessAmount.getAmount(); + Integer actualFruitAmount2 = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount2, actualFruitAmount2); + } + + @Test + void updateStorage_fruitAmountIsGreaterThanInStorage_isNotOk() { + Storage.fruits.put(new Fruit(FRUIT_NAME), FRUIT_AMOUNT); + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transactionWithGreaterAmount); + }, "If amount is greater than in Storage it should throw RuntimeException!"); + + String expectedMessage = " isn't enough!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + void updateStorage_fruitAmountIsNegative_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transactionWithNegativeAmount); + }, "If amount is negative it should throw RuntimeException!"); + + String expectedMessage = "Amount is less then zero!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage));; + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/handler/impl/ReturnOperationHandlerTest.java b/src/test/java/core/basesyntax/service/handler/impl/ReturnOperationHandlerTest.java new file mode 100644 index 0000000000..aabe4633fd --- /dev/null +++ b/src/test/java/core/basesyntax/service/handler/impl/ReturnOperationHandlerTest.java @@ -0,0 +1,82 @@ +package core.basesyntax.service.handler.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ReturnOperationHandlerTest { + private static final String FRUIT_NAME = "banana"; + private static final int FRUIT_AMOUNT = 120; + private static final int FRUIT_NEGATIVE_AMOUNT = -50; + private static final int NUMBER_OF_OPERATION = 2; + private static OperationHandler operationHandler; + private static FruitTransaction transaction; + private static FruitTransaction transactionWithNegativeAmount; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + operationHandler = new ReturnOperationHandler(storageDao); + transaction = new FruitTransaction(); + transactionWithNegativeAmount = new FruitTransaction(); + } + + @BeforeEach + void setUp() { + transaction.setOperation(Operation.RETURN); + transaction.setFruitName(FRUIT_NAME); + transaction.setAmount(FRUIT_AMOUNT); + transactionWithNegativeAmount.setOperation(Operation.RETURN); + transactionWithNegativeAmount.setFruitName(FRUIT_NAME); + transactionWithNegativeAmount.setAmount(FRUIT_NEGATIVE_AMOUNT); + } + + @Test + void updateStorage_isOk() { + operationHandler.updateStorage(transaction); + Integer expectedFruitAmount = FRUIT_AMOUNT; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitInStorage_isOk() { + for (int count = 0; count < NUMBER_OF_OPERATION; count++) { + operationHandler.updateStorage(transaction); + } + Integer expectedFruitAmount = FRUIT_AMOUNT * NUMBER_OF_OPERATION; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitAmountIsNegative_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transactionWithNegativeAmount); + }, "If amount is negative it should throw RuntimeException!"); + + String expectedMessage = "Amount is less then zero!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/handler/impl/SupplyOperationHandlerTest.java b/src/test/java/core/basesyntax/service/handler/impl/SupplyOperationHandlerTest.java new file mode 100644 index 0000000000..fab69556de --- /dev/null +++ b/src/test/java/core/basesyntax/service/handler/impl/SupplyOperationHandlerTest.java @@ -0,0 +1,82 @@ +package core.basesyntax.service.handler.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SupplyOperationHandlerTest { + private static final String FRUIT_NAME = "banana"; + private static final int FRUIT_AMOUNT = 120; + private static final int FRUIT_NEGATIVE_AMOUNT = -50; + private static final int NUMBER_OF_OPERATION = 2; + private static OperationHandler operationHandler; + private static FruitTransaction transaction; + private static FruitTransaction transactionWithNegativeAmount; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + operationHandler = new SupplyOperationHandler(storageDao); + transaction = new FruitTransaction(); + transactionWithNegativeAmount = new FruitTransaction(); + } + + @BeforeEach + void setUp() { + transaction.setOperation(Operation.SUPPLY); + transaction.setFruitName(FRUIT_NAME); + transaction.setAmount(FRUIT_AMOUNT); + transactionWithNegativeAmount.setOperation(Operation.SUPPLY); + transactionWithNegativeAmount.setFruitName(FRUIT_NAME); + transactionWithNegativeAmount.setAmount(FRUIT_NEGATIVE_AMOUNT); + } + + @Test + void updateStorage_isOk() { + operationHandler.updateStorage(transaction); + Integer expectedFruitAmount = FRUIT_AMOUNT; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitInStorage_isOk() { + for (int count = 0; count < NUMBER_OF_OPERATION; count++) { + operationHandler.updateStorage(transaction); + } + Integer expectedFruitAmount = FRUIT_AMOUNT * NUMBER_OF_OPERATION; + Integer actualFruitAmount = Storage.fruits.get(new Fruit(FRUIT_NAME)); + + assertEquals(expectedFruitAmount, actualFruitAmount); + } + + @Test + void updateStorage_fruitAmountIsNegative_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + operationHandler.updateStorage(transactionWithNegativeAmount); + }, "If amount is negative it should throw RuntimeException!"); + + String expectedMessage = "Amount is less then zero!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/impl/CsvWriterTest.java b/src/test/java/core/basesyntax/service/impl/CsvWriterTest.java new file mode 100644 index 0000000000..bc7173b836 --- /dev/null +++ b/src/test/java/core/basesyntax/service/impl/CsvWriterTest.java @@ -0,0 +1,54 @@ +package core.basesyntax.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class CsvWriterTest { + private static final String FILE = "src/test/resources/report.csv"; + private static final String WRONG_FILE = "src/test/badResources/report.csv"; + private static final List EXPECTED_LIST = List.of("fruit,quantity", + "apple,90", "banana,132"); + private static final String DATA = """ + fruit,quantity + apple,90 + banana,132"""; + private static CsvWriter writer; + + @BeforeAll + static void beforeAll() { + writer = new CsvWriter(); + } + + @Test + void writeReportToFile_isOk() { + writer.writeReportToFile(DATA, FILE); + List actualList; + try { + actualList = Files.readAllLines(Path.of(FILE)); + } catch (IOException e) { + throw new RuntimeException("Cant read data from file: " + FILE); + } + + assertEquals(EXPECTED_LIST, actualList); + } + + @Test + void writeReportToFile_badPath_notOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + writer.writeReportToFile(DATA, WRONG_FILE); + },"If path is incorrect it should throw Exception!!!"); + + String expectedMessage = "Can't write data to file: "; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } +} diff --git a/src/test/java/core/basesyntax/service/impl/DataProcessingImplTest.java b/src/test/java/core/basesyntax/service/impl/DataProcessingImplTest.java new file mode 100644 index 0000000000..ce5ee4bfbd --- /dev/null +++ b/src/test/java/core/basesyntax/service/impl/DataProcessingImplTest.java @@ -0,0 +1,93 @@ +package core.basesyntax.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.Operation; +import core.basesyntax.service.DataProcessing; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.service.handler.impl.BalanceOperationHandler; +import core.basesyntax.service.handler.impl.PurchaseOperationHandler; +import core.basesyntax.service.handler.impl.ReturnOperationHandler; +import core.basesyntax.service.handler.impl.SupplyOperationHandler; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.impl.OperationStrategyImpl; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class DataProcessingImplTest { + private static final Fruit BANANA = new Fruit("banana"); + private static final Fruit APPLE = new Fruit("apple"); + private static final int EXPECTED_BANANA_AMOUNT = 125; + private static final int EXPECTED_APPLE_AMOUNT = 35; + private static final List DATA = List.of("b,banana,100", + "s,banana,40", "p,banana,35", "r,banana,20", "b,apple,40", + "r,apple,15", "s,apple,30", "p,apple,50"); + private static final List DATA_INCORRECT_OPERATION = List + .of("b,banana,100", "q,banana,40", "s,banana,35", "p,banana,20"); + private static DataProcessing dataProcessing; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + Map handlersMap = new HashMap<>(); + handlersMap.put(Operation.BALANCE, + new BalanceOperationHandler(storageDao)); + handlersMap.put(Operation.SUPPLY, + new SupplyOperationHandler(storageDao)); + handlersMap.put(Operation.PURCHASE, + new PurchaseOperationHandler(storageDao)); + handlersMap.put(Operation.RETURN, + new ReturnOperationHandler(storageDao)); + OperationStrategy operationStrategy = new OperationStrategyImpl(handlersMap); + dataProcessing = new DataProcessingImpl(operationStrategy); + } + + @Test + void processTransaction_isOk() { + dataProcessing.processTransaction(DATA); + Integer actualBananaAmount = Storage.fruits.get(BANANA); + Integer actualAppleAmount = Storage.fruits.get(APPLE); + + assertEquals(EXPECTED_BANANA_AMOUNT, actualBananaAmount); + assertEquals(EXPECTED_APPLE_AMOUNT, actualAppleAmount); + } + + @Test + void processTransaction_incorrectOperation_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + dataProcessing.processTransaction(DATA_INCORRECT_OPERATION); + }, "If operation does not fount by letter it should throw Exception!!!"); + + String expectedMessage = "There is no such operation by letter "; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + void processTransaction_dataIsNull_isNotOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + dataProcessing.processTransaction(null); + }); + + String expectedMessage = "Data is null!!!"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/service/impl/DataReaderFromCsvTest.java b/src/test/java/core/basesyntax/service/impl/DataReaderFromCsvTest.java new file mode 100644 index 0000000000..478c9afaad --- /dev/null +++ b/src/test/java/core/basesyntax/service/impl/DataReaderFromCsvTest.java @@ -0,0 +1,58 @@ +package core.basesyntax.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import core.basesyntax.service.DataReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class DataReaderFromCsvTest { + private static final String FILE_PATH = "src/test/resources/data.csv"; + private static final String BAD_FILE_PATH = "src/test/resources/badData.csv"; + private static final String DATA = """ + 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"""; + private static final List EXPECTED_LIST = List.of("b,banana,20", + "b,apple,100", "s,banana,100", "p,banana,13", "r,apple,10", + "p,apple, 20", "p,banana,5", "s,banana,50"); + private static DataReader reader; + private static List expected; + + @BeforeAll + static void beforeAll() throws IOException { + reader = new DataReaderFromCsv(); + Files.write(Path.of(FILE_PATH), DATA.getBytes()); + } + + @Test + void readData_isOk() { + List actualList = reader.readData(FILE_PATH); + + assertEquals(EXPECTED_LIST, actualList); + } + + @Test + void readData_fileNotExistOrBadPath_notOk() { + Exception exception = assertThrows(RuntimeException.class, () -> { + reader.readData(BAD_FILE_PATH); + }, "If file does not exist or path is incorrect it should throw Exception!!!"); + + String expectedMessage = "Can't read data from file: "; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } +} diff --git a/src/test/java/core/basesyntax/service/impl/ReportCreatorImplTest.java b/src/test/java/core/basesyntax/service/impl/ReportCreatorImplTest.java new file mode 100644 index 0000000000..6106c2b05f --- /dev/null +++ b/src/test/java/core/basesyntax/service/impl/ReportCreatorImplTest.java @@ -0,0 +1,53 @@ +package core.basesyntax.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import core.basesyntax.service.ReportCreator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ReportCreatorImplTest { + private static final int bananaAmount = 100; + private static final int grapeAmount = 40; + private static final int appleAmount = 90; + private static final Fruit BANANA = new Fruit("banana"); + private static final Fruit GRAPE = new Fruit("grape"); + private static final Fruit APPLE = new Fruit("apple"); + private static final String EXPECTED = """ + fruit,quantity + banana,100 + apple,90 + grape,40"""; + private static ReportCreator reportCreator; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + reportCreator = new ReportCreatorImpl(storageDao); + } + + @BeforeEach + void setUp() { + Storage.fruits.put(BANANA, bananaAmount); + Storage.fruits.put(GRAPE, grapeAmount); + Storage.fruits.put(APPLE, appleAmount); + } + + @Test + void createReport_isOk() { + String actualReport = reportCreator.createReport(); + + assertEquals(EXPECTED, actualReport); + } + + @AfterEach + void tearDown() { + Storage.fruits.clear(); + } +} diff --git a/src/test/java/core/basesyntax/strategy/impl/OperationStrategyImplTest.java b/src/test/java/core/basesyntax/strategy/impl/OperationStrategyImplTest.java new file mode 100644 index 0000000000..ed528985fb --- /dev/null +++ b/src/test/java/core/basesyntax/strategy/impl/OperationStrategyImplTest.java @@ -0,0 +1,72 @@ +package core.basesyntax.strategy.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.service.handler.impl.BalanceOperationHandler; +import core.basesyntax.service.handler.impl.PurchaseOperationHandler; +import core.basesyntax.service.handler.impl.ReturnOperationHandler; +import core.basesyntax.service.handler.impl.SupplyOperationHandler; +import core.basesyntax.strategy.OperationStrategy; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class OperationStrategyImplTest { + private static OperationStrategy operationStrategy; + + @BeforeAll + static void beforeAll() { + StorageDao storageDao = new StorageDaoImpl(); + Map handlers = new HashMap<>(); + handlers.put(Operation.BALANCE, new BalanceOperationHandler(storageDao)); + handlers.put(Operation.SUPPLY, new SupplyOperationHandler(storageDao)); + handlers.put(Operation.PURCHASE, new PurchaseOperationHandler(storageDao)); + handlers.put(Operation.RETURN, new ReturnOperationHandler(storageDao)); + operationStrategy = new OperationStrategyImpl(handlers); + } + + @Test + void getBalanceOperationHandler_isOk() { + OperationHandler actual = operationStrategy.getOperationHandler(Operation.BALANCE); + assertEquals(BalanceOperationHandler.class, actual.getClass()); + } + + @Test + void getSupplyOperationHandler_isOk() { + OperationHandler actual = operationStrategy.getOperationHandler(Operation.SUPPLY); + assertEquals(SupplyOperationHandler.class, actual.getClass()); + } + + @Test + void getPurchaseOperationHandler_isOk() { + OperationHandler actual = operationStrategy.getOperationHandler(Operation.PURCHASE); + assertEquals(PurchaseOperationHandler.class, actual.getClass()); + } + + @Test + void getReturnOperationHandler_isOk() { + OperationHandler actual = operationStrategy.getOperationHandler(Operation.RETURN); + assertEquals(ReturnOperationHandler.class, actual.getClass()); + } + + @Test + void getNull_operationIsNull_isOk() { + OperationHandler actual = operationStrategy.getOperationHandler(null); + assertNull(actual); + } + + @Test + void getOperationHandler_mapIsNull_notOk() { + OperationStrategy strategyWithNullMap = new OperationStrategyImpl(null); + assertThrows(RuntimeException.class, () -> { + strategyWithNullMap.getOperationHandler(Operation.BALANCE); + }, "If map with handlers is Null it should throw Runtime Exception!"); + } +} diff --git a/src/test/resources/.DS_Store b/src/test/resources/.DS_Store new file mode 100644 index 0000000000..a4e79bd477 Binary files /dev/null and b/src/test/resources/.DS_Store differ diff --git a/src/test/resources/data.csv b/src/test/resources/data.csv new file mode 100644 index 0000000000..c1e2881838 --- /dev/null +++ b/src/test/resources/data.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/test/resources/report.csv b/src/test/resources/report.csv new file mode 100644 index 0000000000..3a22c6ec7a --- /dev/null +++ b/src/test/resources/report.csv @@ -0,0 +1,3 @@ +fruit,quantity +apple,90 +banana,132 \ No newline at end of file