Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

๐Ÿš€ 1๋‹จ๊ณ„: ๋ฆฌํŒฉํ„ฐ๋ง(์ƒํ’ˆ) #317

Open
wants to merge 3 commits into
base: dev-yoonjung
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package kitchenpos.products.tobe.common.annotations;


import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Validator {

@AliasFor(
annotation = Component.class
)
String value() default "";

}
56 changes: 56 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/DisplayedName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import kitchenpos.products.tobe.exception.ContainsProfanityException;
import kitchenpos.products.tobe.exception.DisplayedNameEmptyException;

import java.util.Objects;

@Embeddable
public class DisplayedName {

@Column(name = "name", nullable = false)
private String name;

protected DisplayedName() {}

protected DisplayedName(String name, ProfanityValidator profanityValidator) {
validate(name, profanityValidator);
this.name = name;
}

private void validate(String name, ProfanityValidator profanityValidator) {
if (this.isNull(name)) {
throw new DisplayedNameEmptyException();
}
if (!profanityValidator.validate(name)) {
throw new ContainsProfanityException();
}
}

private boolean isNull(String name) {
return Objects.isNull(name);
}

public static DisplayedName of(String name, ProfanityValidator profanityValidator) {
return new DisplayedName(name, profanityValidator);
}

public String value() {
return this.name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DisplayedName that = (DisplayedName) o;
return Objects.equals(name, that.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
}
56 changes: 56 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/Product.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import java.util.UUID;

@Table(name = "product")
@Entity
public class Product {

@Column(name = "id", columnDefinition = "binary(16)")
@Id
private UUID id;

@Embedded
private DisplayedName displayedName;

@Embedded
private ProductPrice price;

protected Product () {}

private Product(UUID id, DisplayedName displayedName, ProductPrice price) {
this.id = id;
this.displayedName = displayedName;
this.price = price;
}

private static Product of(UUID id, DisplayedName displayedName, ProductPrice price) {
return new Product(id, displayedName, price);
}

public static Product of(DisplayedName displayedName, ProductPrice price) {
return of(UUID.randomUUID(), displayedName, price);
}

public void changePrice(ProductPrice price) {
this.price = price;
}

public UUID getId() {
return this.id;
}

public DisplayedName getDisplayedName() {
return this.displayedName;
}

public ProductPrice getProductPrice() {
return this.price;
}
}
62 changes: 62 additions & 0 deletions src/main/java/kitchenpos/products/tobe/domain/ProductPrice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package kitchenpos.products.tobe.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import kitchenpos.products.tobe.exception.NegativeProductPriceException;
import kitchenpos.products.tobe.exception.ProductPriceNullPointException;

import java.math.BigDecimal;
import java.util.Objects;

@Embeddable
public class ProductPrice {

@Column(name = "price", nullable = false)
private BigDecimal price;

protected ProductPrice() {}

protected ProductPrice(BigDecimal price) {
validate(price);
this.price = price;
}

private void validate(BigDecimal price) {
if (this.isNull(price)) {
throw new ProductPriceNullPointException();
}
if (this.isLessThanZero(price)) {
throw new NegativeProductPriceException();
}
}

public static ProductPrice of(BigDecimal price) {
return new ProductPrice(price);
}

public BigDecimal value() {
return this.price;
}

private boolean isNull(BigDecimal price) {
return Objects.isNull(price);
}

private boolean isLessThanZero(BigDecimal price) {
return price.compareTo(BigDecimal.ZERO) < 0;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProductPrice that = (ProductPrice) o;
return Objects.equals(price, that.price);
}

@Override
public int hashCode() {
return Objects.hash(price);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package kitchenpos.products.tobe.domain;

import kitchenpos.products.domain.Product;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface ProductRepository {
Product save(kitchenpos.products.domain.Product product);

Optional<Product> findById(UUID id);

List<Product> findAll();

List<Product> findAllByIdIn(List<UUID> ids);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kitchenpos.products.tobe.domain;

public interface ProfanityValidator {

boolean validate(String text);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.tobe.exception;

public class ContainsProfanityException extends IllegalArgumentException {

public ContainsProfanityException() {
super("์ƒํ’ˆ์˜ ์ด๋ฆ„์—๋Š” ๋น„์†์–ด๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.tobe.exception;

public class DisplayedNameEmptyException extends IllegalArgumentException {

public DisplayedNameEmptyException() {
super("์ƒํ’ˆ์˜ ์ด๋ฆ„์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.tobe.exception;

public class NegativeProductPriceException extends IllegalArgumentException {

public NegativeProductPriceException() {
super("์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์€ 0์›๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kitchenpos.products.tobe.exception;

import java.util.NoSuchElementException;

public class NoSuchProductException extends NoSuchElementException {

public NoSuchProductException() {
super("์ƒํ’ˆ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package kitchenpos.products.tobe.exception;

public class ProductPriceNullPointException extends IllegalArgumentException {

public ProductPriceNullPointException() {
super("์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kitchenpos.products.tobe.infra;

import kitchenpos.products.tobe.common.annotations.Validator;
import kitchenpos.products.infra.PurgomalumClient;
import kitchenpos.products.tobe.domain.ProfanityValidator;

@Validator
public class DefaultProfanityValidator implements ProfanityValidator {

private final PurgomalumClient purgomalumClient;

public DefaultProfanityValidator(PurgomalumClient purgomalumClient) {
this.purgomalumClient = purgomalumClient;
}

public boolean validate(String name) {
return !purgomalumClient.containsProfanity(name);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package kitchenpos.products.domain;
package kitchenpos.products.tobe.infra;

import kitchenpos.products.domain.Product;
import kitchenpos.products.domain.ProductRepository;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package kitchenpos.products.tobe.domain;

import kitchenpos.products.application.FakePurgomalumClient;
import kitchenpos.products.tobe.exception.ContainsProfanityException;
import kitchenpos.products.tobe.exception.DisplayedNameEmptyException;
import kitchenpos.products.tobe.infra.DefaultProfanityValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class DisplayedNameTest {

private ProfanityValidator profanityValidator;

@BeforeEach
void setUp() {
var purgomalumClient = new FakePurgomalumClient();
profanityValidator = new DefaultProfanityValidator(purgomalumClient);
}

@DisplayName("์ƒํ’ˆ์˜ ์ด๋ฆ„์— ์š•์„ค์ด ํฌํ•จ๋˜๋ฉด ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.")
@ValueSource(strings = {"๋น„์†์–ด", "์š•์„ค์ด ํฌํ•จ๋œ ์ด๋ฆ„"})
@ParameterizedTest
void containsProfanity(final String name) {
assertThatThrownBy(() -> DisplayedName.of(name, profanityValidator))
.isInstanceOf(ContainsProfanityException.class);
}

@DisplayName("์ƒํ’ˆ์˜ ์ด๋ฆ„์ด ๋น„์–ด์žˆ์œผ๋ฉด ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.")
@NullSource
@ParameterizedTest
void emptyPrice(final String name) {
assertThatThrownBy(() -> DisplayedName.of(name, profanityValidator))
.isInstanceOf(DisplayedNameEmptyException.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package kitchenpos.products.tobe.domain;

import kitchenpos.products.tobe.exception.NegativeProductPriceException;
import kitchenpos.products.tobe.exception.ProductPriceNullPointException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

import java.math.BigDecimal;

import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class ProductPriceTest {

@DisplayName("์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์ด ๋งˆ์ด๋„ˆ์Šค์ด๋ฉด ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.")
@ValueSource(strings = "-1000")
@ParameterizedTest
void invalidPrice(final BigDecimal price) {
assertThatThrownBy(() -> ProductPrice.of(price))
.isInstanceOf(NegativeProductPriceException.class);
}

@DisplayName("์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์ด ๋น„์–ด์žˆ์œผ๋ฉด ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.")
@NullSource
@ParameterizedTest
void emptyPrice(final BigDecimal price) {
assertThatThrownBy(() -> ProductPrice.of(price))
.isInstanceOf(ProductPriceNullPointException.class);
}



}
Loading