diff --git a/src/main/java/coordinate/MainApplication.java b/src/main/java/coordinate/MainApplication.java new file mode 100644 index 0000000..c845519 --- /dev/null +++ b/src/main/java/coordinate/MainApplication.java @@ -0,0 +1,20 @@ +package coordinate; + +import coordinate.figure.Figure; +import coordinate.figure.FigureFactory; +import coordinate.figure.FigureSize; +import coordinate.graph.Graph; +import coordinate.io.ConsoleInputHandler; +import coordinate.io.ConsoleOutputHandler; + +public class MainApplication { + private static final ConsoleInputHandler inputHandler = new ConsoleInputHandler(); + private static final ConsoleOutputHandler outputHandler = new ConsoleOutputHandler(); + + public static void main(String[] args) { + FigureSize figureSize = inputHandler.getFigureSize(); + Figure figure = FigureFactory.create(figureSize); + Graph graph = Graph.from(figure); + outputHandler.printGraph(graph); + } +} \ No newline at end of file diff --git a/src/main/java/coordinate/exception/CoordinateException.java b/src/main/java/coordinate/exception/CoordinateException.java new file mode 100644 index 0000000..e2d71bd --- /dev/null +++ b/src/main/java/coordinate/exception/CoordinateException.java @@ -0,0 +1,8 @@ +package coordinate.exception; + +public class CoordinateException extends RuntimeException { + + public CoordinateException(String message) { + super(message); + } +} diff --git a/src/main/java/coordinate/figure/Figure.java b/src/main/java/coordinate/figure/Figure.java new file mode 100644 index 0000000..d42ae3e --- /dev/null +++ b/src/main/java/coordinate/figure/Figure.java @@ -0,0 +1,8 @@ +package coordinate.figure; + +public interface Figure { + + double calculate(); + + boolean isMark(int x, int y); +} diff --git a/src/main/java/coordinate/figure/FigureFactory.java b/src/main/java/coordinate/figure/FigureFactory.java new file mode 100644 index 0000000..e6c1e6f --- /dev/null +++ b/src/main/java/coordinate/figure/FigureFactory.java @@ -0,0 +1,8 @@ +package coordinate.figure; + +public class FigureFactory { + + public static Figure create(FigureSize figureSize) { + return FigureType.create(figureSize); + } +} diff --git a/src/main/java/coordinate/figure/FigureSize.java b/src/main/java/coordinate/figure/FigureSize.java new file mode 100644 index 0000000..a7ec5c6 --- /dev/null +++ b/src/main/java/coordinate/figure/FigureSize.java @@ -0,0 +1,33 @@ +package coordinate.figure; + +import coordinate.point.Coordinate; +import coordinate.point.Points; +import coordinate.utils.StringUtils; +import java.util.List; +import java.util.stream.Collectors; + +public class FigureSize { + + private final List figureSizes; + + private FigureSize(List figureSizes) { + this.figureSizes = figureSizes; + } + + public static FigureSize from(String userInputFigureSize) { + List splitedByHyphen = StringUtils.splitByHyphen(userInputFigureSize); + + List figureSizes = splitedByHyphen.stream() + .map(Coordinate::from) + .collect(Collectors.toList()); + + return new FigureSize(figureSizes); + } + + public Points toPoints() { + return Points.from(figureSizes.stream() + .map(Coordinate::toPoint) + .collect(Collectors.toList())); + } + +} diff --git a/src/main/java/coordinate/figure/FigureType.java b/src/main/java/coordinate/figure/FigureType.java new file mode 100644 index 0000000..4b0d005 --- /dev/null +++ b/src/main/java/coordinate/figure/FigureType.java @@ -0,0 +1,45 @@ +package coordinate.figure; + +import coordinate.exception.CoordinateException; +import coordinate.messages.ErrorMessage; +import coordinate.point.Points; +import java.util.Arrays; + +public enum FigureType { + LINE(2) { + @Override + public Figure createFigure(Points points) { + return Line.from(points); + } + }, + RECTANGLE(4) { + @Override + public Figure createFigure(Points points) { + return Rectangle.from(points); + } + }, + TRIANGLE(3) { + @Override + public Figure createFigure(Points points) { + return Triangle.from(points); + } + }; + + private final int pointsSize; + + FigureType(int pointsSize) { + this.pointsSize = pointsSize; + } + + public abstract Figure createFigure(Points points); + + public static Figure create(FigureSize figureSize) { + Points points = figureSize.toPoints(); + + return Arrays.stream(values()) + .filter(type -> type.pointsSize == points.size()) + .findFirst() + .orElseThrow(() -> new CoordinateException(ErrorMessage.invalidFigureSize)) + .createFigure(points); + } +} diff --git a/src/main/java/coordinate/figure/Line.java b/src/main/java/coordinate/figure/Line.java new file mode 100644 index 0000000..24b27c1 --- /dev/null +++ b/src/main/java/coordinate/figure/Line.java @@ -0,0 +1,59 @@ +package coordinate.figure; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.List; + +public class Line implements Figure { + + private final Points points; + + private Line(Points points) { + this.points = points; + } + + public static Line from(Points points) { + return new Line(points); + } + + @Override + public String toString() { + return String.format("두 점 사이의 거리는: " + calculate()); + } + + @Override + public boolean isMark(int x, int y) { + return points.isMarkedAt(x, y); + } + + /** + * 제곱근((A.x - B.x)^제곱 + (A.y - B.y)^제곱) + */ + @Override + public double calculate() { + List points = this.points.getPoints(); + + Point firstPoint = getFirstPoint(points); + Point secondPoint = getSecondPoint(points); + + return calculateDistanceBetweenPoints(firstPoint, secondPoint); + } + + private Point getFirstPoint(List points) { + return points.get(0); + } + + private Point getSecondPoint(List points) { + return points.get(1); + } + + private double calculateDistanceBetweenPoints(Point point1, Point point2) { + double subX = square(point1.subtractionByX(point2)); + double subY = square(point1.subtractionByY(point2)); + return Math.sqrt(subX + subY); + } + + private double square(int value) { + return Math.pow(value, 2); + } +} diff --git a/src/main/java/coordinate/figure/Rectangle.java b/src/main/java/coordinate/figure/Rectangle.java new file mode 100644 index 0000000..40bc276 --- /dev/null +++ b/src/main/java/coordinate/figure/Rectangle.java @@ -0,0 +1,58 @@ +package coordinate.figure; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.List; + +public class Rectangle implements Figure { + + private final Points points; + + private Rectangle(Points points) { + this.points = points; + } + + public static Rectangle from(Points points) { + return new Rectangle(points); + } + + @Override + public boolean isMark(int x, int y) { + return points.isMarkedAt(x, y); + } + + @Override + public String toString() { + return "사각형의 넓이는 " + (int) calculate(); + } + + /** + * width * height + */ + @Override + public double calculate() { + List points = this.points.getPoints(); + + Point leftBottomPoint = getLeftBottomPoint(points); + Point rightTopPoint = getRightTopPoint(points); + + return getWidth(leftBottomPoint, rightTopPoint) * getHeight(leftBottomPoint, rightTopPoint); + } + + private Point getLeftBottomPoint(List points) { + return points.get(0); + } + + private static Point getRightTopPoint(List points) { + return points.get(2); + } + + private double getWidth(Point point1, Point point2) { + return Math.abs(point1.subtractionByX(point2)); + } + + private double getHeight(Point point1, Point point2) { + return Math.abs(point1.subtractionByY(point2)); + } + +} diff --git a/src/main/java/coordinate/figure/Triangle.java b/src/main/java/coordinate/figure/Triangle.java new file mode 100644 index 0000000..6f8bfd0 --- /dev/null +++ b/src/main/java/coordinate/figure/Triangle.java @@ -0,0 +1,78 @@ +package coordinate.figure; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.ArrayList; +import java.util.List; + +public class Triangle implements Figure{ + + private final Points points; + + private Triangle(Points points) { + this.points = points; + } + + public static Triangle from(Points points) { + return new Triangle(points); + } + + @Override + public boolean isMark(int x, int y) { + return points.isMarkedAt(x, y); + } + + @Override + public String toString() { + return "삼각형의 넓이는 " + (double) Math.round(calculate()); + } + + @Override + public double calculate() { + List distances = getDistances(); + double half = getHalf(distances); + return getTriangleWidthByDistances(distances, half); + } + + private List getDistances() { + List pointsArray = points.getPoints(); + List distances = new ArrayList<>(); + + for (int i = 0; i < points.size(); i++) { + int nextIndex = getPointNextIndex(i); + distances.add(getPointsBetweenDistance(pointsArray.get(i), pointsArray.get(nextIndex))); + } + + return distances; + } + + private int getPointNextIndex(int index) { + int pointSize = points.size(); + + if (index == pointSize-1) { + return 0; + } + + return index + 1; + } + + private double getPointsBetweenDistance(Point point1, Point point2) { + Line line = Line.from(Points.from(List.of(point1, point2))); + return line.calculate(); + } + + private double getHalf(List distances) { + return distances.stream().mapToDouble(Double::doubleValue).sum() / 2; + } + + private double getTriangleWidthByDistances(List distances, double half) { + double width = 1; + for (double distance : distances) { + width *= (half - distance); + } + width *= half; + + return Math.sqrt(width); + } + +} diff --git a/src/main/java/coordinate/graph/Graph.java b/src/main/java/coordinate/graph/Graph.java new file mode 100644 index 0000000..ff64c2a --- /dev/null +++ b/src/main/java/coordinate/graph/Graph.java @@ -0,0 +1,94 @@ +package coordinate.graph; + +import coordinate.figure.Figure; +import java.util.stream.IntStream; + +public class Graph { + + public static final int MAX_VALUE = 24; + public static final int MIN_VALUE = 0; + public static final int MAX_INT_RANGE = 25; + public static final String PLUS_MARK = "+"; + private static final String PIPE = "|"; + private static final String DOUBLE_HYPHEN = "--"; + private static final String NEW_LINE = System.lineSeparator(); + public static final String POINT_MARK = "•"; + public static final String SPACE = " "; + + private final StringBuilder graphBuilder = new StringBuilder(); + private final Figure figure; + + private Graph(Figure figure) { + this.figure = figure; + } + + public static Graph from(Figure figure) { + return new Graph(figure); + } + + public StringBuilder draw() { + verticalDrawAndPoint(); + horizontalDraw(); + distanceBetweenPointsResult(); + return graphBuilder; + } + + private void distanceBetweenPointsResult() { + graphBuilder.append(NEW_LINE); + graphBuilder.append(figure.toString()); + } + + private void verticalDrawAndPoint() { + for (int y = MAX_VALUE; y > MIN_VALUE; y--) { + verticalDrawNumberWithPipe(y); + drawPoint(y); + graphBuilder.append(NEW_LINE); + } + } + + private void verticalDrawNumberWithPipe(int y) { + if (isEvenNumber(y)) { + graphBuilder.append(String.format("%3d|", y)); + return; + } + + graphBuilder.append(String.format("%4s", PIPE)); + } + + private void drawPoint(int y) { + for (int x = 0; x < MAX_INT_RANGE; x++) { + markAdd(x, y, figure); + } + } + + private void markAdd(int x, int y, Figure figure) { + if (figure.isMark(x, y)) { + graphBuilder.append(POINT_MARK); + return; + } + + graphBuilder.append(String.format("%2s", SPACE)); + } + + private void horizontalDraw() { + horizontalLineDraw(); + horizontalNumberDraw(); + } + + private void horizontalNumberDraw() { + IntStream.range(MIN_VALUE, MAX_INT_RANGE) + .filter(this::isEvenNumber) + .forEach(x -> graphBuilder.append(String.format("%4d", x))); + graphBuilder.append(NEW_LINE); + } + + private void horizontalLineDraw() { + graphBuilder.append(String.format("%4s", PLUS_MARK)); + IntStream.range(MIN_VALUE, MAX_VALUE).forEach(i -> graphBuilder.append(DOUBLE_HYPHEN)); + graphBuilder.append(NEW_LINE); + } + + private boolean isEvenNumber(int value) { + return value % 2 == MIN_VALUE; + } +} diff --git a/src/main/java/coordinate/io/ConsoleInputHandler.java b/src/main/java/coordinate/io/ConsoleInputHandler.java new file mode 100644 index 0000000..1c01f81 --- /dev/null +++ b/src/main/java/coordinate/io/ConsoleInputHandler.java @@ -0,0 +1,26 @@ +package coordinate.io; + +import coordinate.exception.CoordinateException; +import coordinate.figure.FigureSize; +import coordinate.messages.SystemMessage; +import java.util.Scanner; + +public class ConsoleInputHandler { + + private final Scanner scanner = new Scanner(System.in); + + public FigureSize getFigureSize() { + try { + return FigureSize.from(inputFromUser()); + } catch (CoordinateException e) { + System.out.println(e.getMessage()); + return getFigureSize(); + } + } + + private String inputFromUser() { + System.out.println(SystemMessage.inputFigureSize); + return scanner.nextLine(); + } + +} diff --git a/src/main/java/coordinate/io/ConsoleOutputHandler.java b/src/main/java/coordinate/io/ConsoleOutputHandler.java new file mode 100644 index 0000000..5360a3d --- /dev/null +++ b/src/main/java/coordinate/io/ConsoleOutputHandler.java @@ -0,0 +1,10 @@ +package coordinate.io; + +import coordinate.graph.Graph; + +public class ConsoleOutputHandler { + + public void printGraph(Graph graph) { + System.out.println(graph.draw().toString()); + } +} diff --git a/src/main/java/coordinate/messages/ErrorMessage.java b/src/main/java/coordinate/messages/ErrorMessage.java new file mode 100644 index 0000000..9ad09d7 --- /dev/null +++ b/src/main/java/coordinate/messages/ErrorMessage.java @@ -0,0 +1,10 @@ +package coordinate.messages; + +public class ErrorMessage { + + public static final String invalidPoint = "좌표는 최소 0부터 최대 24까지 입력 할 수 있습니다."; + public static final String hyphenMustHave = "두 점의 좌표를 구분을 위해 '-' 필수로 입력 해야 합니다."; + public static final String regexNotMatched = "좌표는 '(x, y) 형식으로 입력하며 숫자만 입력 해야 합니다."; + public static final String invalidFigureSize = "해당 좌표로 도형을 생성 할 수 없습니다."; + +} diff --git a/src/main/java/coordinate/messages/SystemMessage.java b/src/main/java/coordinate/messages/SystemMessage.java new file mode 100644 index 0000000..8e8137c --- /dev/null +++ b/src/main/java/coordinate/messages/SystemMessage.java @@ -0,0 +1,6 @@ +package coordinate.messages; + +public class SystemMessage { + + public static final String inputFigureSize = "좌표를 입력하세요."; +} diff --git a/src/main/java/coordinate/point/Coordinate.java b/src/main/java/coordinate/point/Coordinate.java new file mode 100644 index 0000000..c635807 --- /dev/null +++ b/src/main/java/coordinate/point/Coordinate.java @@ -0,0 +1,39 @@ +package coordinate.point; + +import coordinate.utils.StringUtils; +import java.util.List; +import java.util.Objects; + +public class Coordinate { + + private final List coordinate; + + private Coordinate(List coordinate) { + this.coordinate = coordinate; + } + + public static Coordinate from(String coordinateStringWithBracket) { + return new Coordinate(StringUtils.extractFromStringToIntegerByRegex(coordinateStringWithBracket)); + } + + public Point toPoint() { + return Point.of(coordinate.get(0), coordinate.get(1)); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Coordinate that = (Coordinate) o; + return Objects.equals(coordinate, that.coordinate); + } + + @Override + public int hashCode() { + return Objects.hashCode(coordinate); + } +} diff --git a/src/main/java/coordinate/point/Point.java b/src/main/java/coordinate/point/Point.java new file mode 100644 index 0000000..104b5d1 --- /dev/null +++ b/src/main/java/coordinate/point/Point.java @@ -0,0 +1,59 @@ +package coordinate.point; + +import coordinate.exception.CoordinateException; +import coordinate.messages.ErrorMessage; +import java.util.Objects; + +public class Point { + + private static final int MIN_VALUE = 0; + private static final int MAX_VALUE = 24; + private final int x; + private final int y; + + private Point(int x, int y) { + if (validateInputValue(x) || validateInputValue(y)) { + throw new CoordinateException(ErrorMessage.invalidPoint); + } + + this.x = x; + this.y = y; + } + + public static Point of(int x, int y) { + return new Point(x, y); + } + + public boolean isSamePosition(int x, int y) { + return this.x == x && this.y == y; + } + + public int subtractionByX(Point anotherPoint) { + return x - anotherPoint.x; + } + + public int subtractionByY(Point anotherPoint) { + return y - anotherPoint.y; + } + + private boolean validateInputValue(int point) { + return point < MIN_VALUE || point > MAX_VALUE; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Point point = (Point) o; + return x == point.x && y == point.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } +} diff --git a/src/main/java/coordinate/point/Points.java b/src/main/java/coordinate/point/Points.java new file mode 100644 index 0000000..239bfaf --- /dev/null +++ b/src/main/java/coordinate/point/Points.java @@ -0,0 +1,48 @@ +package coordinate.point; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Points { + + private final List points; + + private Points(List points) { + this.points = points; + } + + public static Points from(List points) { + return new Points(points); + } + + public boolean isMarkedAt(int x, int y) { + return points.stream() + .anyMatch(point -> point.isSamePosition(x, y)); + } + + public int size() { + return points.size(); + } + + public List getPoints() { + return new ArrayList<>(points); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Points pointList = (Points) o; + return Objects.equals(points, pointList.points); + } + + @Override + public int hashCode() { + return Objects.hashCode(points); + } +} diff --git a/src/main/java/coordinate/utils/StringUtils.java b/src/main/java/coordinate/utils/StringUtils.java new file mode 100644 index 0000000..62ae7fd --- /dev/null +++ b/src/main/java/coordinate/utils/StringUtils.java @@ -0,0 +1,39 @@ +package coordinate.utils; + +import coordinate.exception.CoordinateException; +import coordinate.messages.ErrorMessage; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class StringUtils { + + public static List splitByHyphen(String string) { + if (!string.contains("-")) { + throw new CoordinateException(ErrorMessage.hyphenMustHave); + } + + return List.of(string.split("-")); + } + + public static List extractFromStringToIntegerByRegex(String string) { + String regex = "\\((\\d+),(\\d+)\\)"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(string); + + if (matcher.matches()) { + return IntStream.range(1, matcher.groupCount() + 1) + .mapToObj(i -> stringMatcherToInt(matcher, i)) + .collect(Collectors.toList()); + } + + throw new CoordinateException(ErrorMessage.regexNotMatched); + } + + private static int stringMatcherToInt(Matcher matcher, int groupIndex) { + return Integer.parseInt(matcher.group(groupIndex)); + } + +} diff --git a/src/test/java/coordinate/figure/FigureFactoryTest.java b/src/test/java/coordinate/figure/FigureFactoryTest.java new file mode 100644 index 0000000..ba68206 --- /dev/null +++ b/src/test/java/coordinate/figure/FigureFactoryTest.java @@ -0,0 +1,37 @@ +package coordinate.figure; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class FigureFactoryTest { + + @Test + @DisplayName("2개의 좌표를 입력 하면 Line 객체를 반환한다") + void testFigureFactoryCreateLine() { + + // Given + FigureSize figureSize = FigureSize.from("(10,10)-(14,15)"); + + // When + Figure figure = FigureFactory.create(figureSize); + + // Then + assertThat(figure).isInstanceOf(Line.class); + } + + @Test + @DisplayName("4개의 좌표를 입력 하면 Rectangle 객체를 반환한다") + void testFigureFactoryCreateRectangle() { + + // Given + FigureSize figureSize = FigureSize.from("(10,10)-(22,10)-(22,18)-(10,18)"); + + // When + Figure figure = FigureFactory.create(figureSize); + + // Then + assertThat(figure).isInstanceOf(Rectangle.class); + } +} diff --git a/src/test/java/coordinate/figure/FigureTypeTest.java b/src/test/java/coordinate/figure/FigureTypeTest.java new file mode 100644 index 0000000..ccebb28 --- /dev/null +++ b/src/test/java/coordinate/figure/FigureTypeTest.java @@ -0,0 +1,56 @@ +package coordinate.figure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import coordinate.exception.CoordinateException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class FigureTypeTest { + + @Test + @DisplayName("2개의 좌표를 입력하면 Line 객체를 반환한다") + void testLineFigureType() { + // Given + FigureSize figureSize = FigureSize.from("(10,10)-(14,15)"); + + // When + Figure line = FigureType.create(figureSize); + + // Then + assertThat(line).isInstanceOf(Line.class); + } + + @Test + @DisplayName("4개의 좌표를 입력하면 Rectangle 객체를 반환한다") + void testRectangleFigureType() { + // Given + FigureSize figureSize = FigureSize.from("(10,10)-(22,10)-(22,18)-(10,18)"); + + // When + Figure rectangle = FigureType.create(figureSize); + + // Then + assertThat(rectangle).isInstanceOf(Rectangle.class); + } + + @ParameterizedTest + @DisplayName("정의 되지 않은 좌표 개 수를 입력하면 예외를 반환한다") + @CsvSource(value = {"(10,10)-(1,1)-(1,2)-(1,3)-(1,4):", "(1,1)-"}, delimiter = ':') + void testInvalidCoordinateSizes(String testFigureSize) { + // Given + FigureSize figureSize = FigureSize.from(testFigureSize); + + assertThatThrownBy(() -> { + // When + FigureType.create(figureSize); + }) + // Then + .hasMessage("해당 좌표로 도형을 생성 할 수 없습니다.") + .isInstanceOf(CoordinateException.class); + } + +} diff --git a/src/test/java/coordinate/figure/LineTest.java b/src/test/java/coordinate/figure/LineTest.java new file mode 100644 index 0000000..81e512e --- /dev/null +++ b/src/test/java/coordinate/figure/LineTest.java @@ -0,0 +1,81 @@ +package coordinate.figure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class LineTest { + + private static Points points; + + @BeforeAll + static void setUp() { + points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15))); + } + + @ParameterizedTest + @DisplayName("두 점의 위치와 좌표 위치가 같을 때 마크 표시 여부가 True 가 된다") + @CsvSource(value = {"10,10", "14,15"}) + void testLineIsMark(int x, int y) { + + // Given + Line line = Line.from(points); + + // When + boolean isMark = line.isMark(x, y); + + // Then + assertThat(isMark).isTrue(); + } + + @ParameterizedTest + @DisplayName("두 점의 위치와 좌표 위치가 다르면 마크 표시 여부가 False 이다") + @CsvSource(value = {"10,11", "14,16"}) + void testLineIsNotMark(int x, int y) { + + // Given + Line line = Line.from(points); + + // When + boolean isMark = line.isMark(x, y); + + // Then + assertThat(isMark).isFalse(); + } + + @Test + @DisplayName("두 점사이의 거리를 계산한 값을 검증한다") + void testLineDistanceBetweenPoints() { + + // Given + Line line = Line.from(points); + + // When + double distance = line.calculate(); + + // Then + assertThat(distance).isEqualTo(6.40312, offset(0.00099)); + } + + @Test + @DisplayName("Line 객체를 문자열로 반환할 시 두 점 사이의 거리를 출력 해야한다") + void testLineToString() { + + // Given + Line line = Line.from(points); + + // When + String string = line.toString(); + + // Then + assertThat(string).isEqualTo("두 점 사이의 거리는: " + 6.4031242374328485); + } +} diff --git a/src/test/java/coordinate/figure/RectangleTest.java b/src/test/java/coordinate/figure/RectangleTest.java new file mode 100644 index 0000000..82b5f0c --- /dev/null +++ b/src/test/java/coordinate/figure/RectangleTest.java @@ -0,0 +1,82 @@ +package coordinate.figure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class RectangleTest { + + private static Points points; + + @BeforeAll + static void setUp() { + points = Points.from(List.of(Point.of(10, 10), Point.of(22, 10), Point.of(22, 18), Point.of(10, 18))); + } + + + @ParameterizedTest + @DisplayName("네 점의 위치와 좌표 위치가 같을 때 마크 표시 여부가 True 가 된다") + @CsvSource(value = {"10,10", "22,10", "22,18", "10,18"}) + void testRectangleIsMark(int x, int y) { + + // Given + Rectangle rectangle = Rectangle.from(points); + + // When + boolean isMark = rectangle.isMark(x, y); + + // Then + assertThat(isMark).isTrue(); + } + + @ParameterizedTest + @DisplayName("네 점의 위치와 좌표 위치가 다른 경우 마크 표시 여부는 False 이다") + @CsvSource(value = {"10,11", "2,10", "22,13", "5,18"}) + void testRectangleIsNotMark(int x, int y) { + + // Given + Rectangle rectangle = Rectangle.from(points); + + // When + boolean isMark = rectangle.isMark(x, y); + + // Then + assertThat(isMark).isFalse(); + } + + @Test + @DisplayName("사각형의 면접을 계산하는 반환 값을 검증한다") + void testRectangleCalculate() { + + // Given + Rectangle rectangle = Rectangle.from(points); + + // When + double result = rectangle.calculate(); + + // Then + assertThat(result).isEqualTo(96.0, offset(0.00099)); + } + + @Test + @DisplayName("Rectangle 객체를 문자열로 변환 할 시 사각형의 넓이를 반환한다") + void testRectangleToString() { + + // Given + Rectangle rectangle = Rectangle.from(points); + + // When + String string = rectangle.toString(); + + // Then + assertThat(string).isEqualTo("사각형의 넓이는 " + 96); + } +} diff --git a/src/test/java/coordinate/figure/TriangleTest.java b/src/test/java/coordinate/figure/TriangleTest.java new file mode 100644 index 0000000..1d2e18a --- /dev/null +++ b/src/test/java/coordinate/figure/TriangleTest.java @@ -0,0 +1,49 @@ +package coordinate.figure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; + +import coordinate.point.Point; +import coordinate.point.Points; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class TriangleTest { + + private static Points points; + + @BeforeAll + static void setUp() { + points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15), Point.of(20, 8))); + } + + @Test + @DisplayName("삼각형의 면적을 계산하는 반환 값을 검증한다") + void testTriangleCalculate() { + // Given + Triangle rectangle = Triangle.from(points); + + // When + double result = rectangle.calculate(); + + // Then + assertThat(result).isEqualTo(29.0, offset(0.00099)); + } + + @Test + @DisplayName("Rectangle 객체를 문자열로 변환 할 시 사각형의 넓이를 반환한다") + void testTriangleToString() { + + // Given + Triangle rectangle = Triangle.from(points); + + // When + String string = rectangle.toString(); + + // Then + assertThat(string).isEqualTo("삼각형의 넓이는 " + 29.0); + } + +} diff --git a/src/test/java/coordinate/point/CoordinateTest.java b/src/test/java/coordinate/point/CoordinateTest.java new file mode 100644 index 0000000..4162f57 --- /dev/null +++ b/src/test/java/coordinate/point/CoordinateTest.java @@ -0,0 +1,55 @@ +package coordinate.point; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import coordinate.exception.CoordinateException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class CoordinateTest { + + + @Test + @DisplayName("좌표는 '(x,y)' 형태로 입력해야 한다.") + void testCoordinateValidation() { + // Given + String coordinateInput = "(10,10)"; + + // When + Coordinate coordinate = Coordinate.from(coordinateInput); + + // Then + assertThat(coordinate.toPoint()).isEqualTo(Point.of(10, 10)); + } + + @Test + @DisplayName("좌표를 입력할 때 괄호 형식을 지키지 않으면 예외를 반환한다") + void testCoordinateBracketValidation() { + // Given + String coordinateInput = "10,10"; + + assertThatThrownBy(() -> { + // When + Coordinate.from(coordinateInput); + }) + // Then + .hasMessage("좌표는 '(x, y) 형식으로 입력하며 숫자만 입력 해야 합니다.") + .isInstanceOf(CoordinateException.class); + } + + @Test + @DisplayName("좌표에 입력한 값이 숫자가 아닌 경우 예외를 반환한다") + void testCoordinateValueValidation() { + // Given + String coordinateInput = "(10,a)"; + + assertThatThrownBy(() -> { + // When + Coordinate.from(coordinateInput); + }) + // Then + .hasMessage("좌표는 '(x, y) 형식으로 입력하며 숫자만 입력 해야 합니다.") + .isInstanceOf(CoordinateException.class); + } +} diff --git a/src/test/java/coordinate/point/PointTest.java b/src/test/java/coordinate/point/PointTest.java new file mode 100644 index 0000000..647e787 --- /dev/null +++ b/src/test/java/coordinate/point/PointTest.java @@ -0,0 +1,94 @@ +package coordinate.point; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import coordinate.exception.CoordinateException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class PointTest { + + @ParameterizedTest + @DisplayName("좌표는 0 ~ 24까지의 값만 입력할 수 있다") + @CsvSource({"0,24"}) + void testPointValidateByMinMaxValues(int x, int y) { + // Given + Point given = Point.of(0, 24); + + // When + Point point = Point.of(x, y); + + // Then + assertThat(point).isEqualTo(given); + } + + @ParameterizedTest + @DisplayName("입력한 좌표가 0 ~ 24 범위를 벗어나면 예외를 반환한다") + @CsvSource({"-1,24", "0,25"}) + void testPointValidateByMinMaxValuesException(int x, int y) { + assertThatThrownBy(() -> { + // Given & When + Point.of(x, y); + }) + // Then + .hasMessage("좌표는 최소 0부터 최대 24까지 입력 할 수 있습니다.") + .isInstanceOf(CoordinateException.class); + } + + @Test + @DisplayName("좌표값이 같을 때 마크 표시 상태값이 활성화된다.") + void testPointMarkIsTrue() { + // Given + Point point = Point.of(10, 10); + + // When + boolean markIsEnabled = point.isSamePosition(10, 10); + + // Then + assertThat(markIsEnabled).isTrue(); + } + + @Test + @DisplayName("좌표값이 같지 않으면 마크 표시 상태값이 활성화 되지 않는다.") + void testPointMarkIsFalse() { + // Given + Point point = Point.of(10, 10); + + // When + boolean markIsEnabled = point.isSamePosition(10, 11); + + // Then + assertThat(markIsEnabled).isFalse(); + } + + @Test + @DisplayName("두 점에서 X좌표 끼리 뺄셈 연산을 한다.") + void testSubtractByX() { + // Given + Point firstPoint = Point.of(10, 10); + Point secondPoint = Point.of(20, 20); + + // When + int result = firstPoint.subtractionByX(secondPoint); + + // Then + assertThat(result).isEqualTo(-10); + } + + @Test + @DisplayName("두 점에서 Y좌표 끼리 뺄셈 연산을 한다.") + void testSubtractByY() { + // Given + Point firstPoint = Point.of(10, 14); + Point secondPoint = Point.of(20, 20); + + // When + int result = firstPoint.subtractionByY(secondPoint); + + // Then + assertThat(result).isEqualTo(-6); + } +} diff --git a/src/test/java/coordinate/point/PointsTest.java b/src/test/java/coordinate/point/PointsTest.java new file mode 100644 index 0000000..69faaf3 --- /dev/null +++ b/src/test/java/coordinate/point/PointsTest.java @@ -0,0 +1,80 @@ +package coordinate.point; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +public class PointsTest { + + @ParameterizedTest + @DisplayName("그래프의 좌표 값과 포인트의 좌표 값이 일치할 경우 마크 표시를 활성화한다") + @CsvSource(value = {"10,10", "14,15"}) + void testPointsMark(int x, int y) { + // Given + Points points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15))); + + // When + boolean markedAt = points.isMarkedAt(x, y); + + // Then + assertThat(markedAt).isTrue(); + } + + @ParameterizedTest + @DisplayName("그래프의 좌표 값과 포인트의 좌표 값이 일치하지 않을 경우 마크 표시가 활성화 되지 않는다") + @CsvSource(value = {"11,10", "14,16"}) + void testPointsIsNotMark(int x, int y) { + // Given + Points points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15))); + + // When + boolean markedAt = points.isMarkedAt(x, y); + + // Then + assertThat(markedAt).isFalse(); + } + + @Test + @DisplayName("입력한 좌표가 2개일 때 Points 객체의 사이즈는 2여야한다") + void testPointsSizeTwo() { + // Given + Points points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15))); + + // When + int size = points.size(); + + // Then + assertThat(size).isEqualTo(2); + } + + @Test + @DisplayName("입력한 좌표가 4개일 때 Points 객체의 사이즈는 4여야한다") + void testPointsSizeFour() { + // Given + Points points = Points.from(List.of(Point.of(10, 10), Point.of(20, 20), Point.of(22, 18), Point.of(10, 18))); + + // When + int size = points.size(); + + // Then + assertThat(size).isEqualTo(4); + } + + @Test + @DisplayName("Points 객체가 가진 Point 배열을 반환한다") + void testGetPoints() { + // Given + Points points = Points.from(List.of(Point.of(10, 10), Point.of(14, 15))); + List pointList = List.of(Point.of(10, 10), Point.of(14, 15)); + + // When + List getPoints = points.getPoints(); + + // Then + assertThat(getPoints).isEqualTo(pointList); + } +} diff --git a/src/test/java/coordinate/utils/StringUtilsTest.java b/src/test/java/coordinate/utils/StringUtilsTest.java new file mode 100644 index 0000000..114dbe9 --- /dev/null +++ b/src/test/java/coordinate/utils/StringUtilsTest.java @@ -0,0 +1,55 @@ +package coordinate.utils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import coordinate.exception.CoordinateException; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class StringUtilsTest { + + @Test + @DisplayName("문자열을 '-'을 기준으로 분리한다") + void testSplitByHyphen() { + // Given + String string = "10-11"; + + // When + List strings = StringUtils.splitByHyphen(string); + + // Then + assertThat(strings).contains("10", "11"); + assertThat(strings.size()).isEqualTo(2); + } + + @Test + @DisplayName("'-'이 포함 되지 않은 문자열을 분리 시킬 때 예외를 반환한다") + void testSplitToNotContainsHyphenString() { + // Given + String string = "10, 11"; + + assertThatThrownBy(() -> { + // When + StringUtils.splitByHyphen(string); + }) + // Then + .hasMessage("두 점의 좌표를 구분을 위해 '-' 필수로 입력 해야 합니다.") + .isInstanceOf(CoordinateException.class); + } + + @Test + @DisplayName("좌표 형식에 맞는 문자열을 추출 하여 숫자로 변환한다") + void testExtractFromCoordinateString() { + // Given + String coordinateString = "(10,11)"; + + // When + List integers = StringUtils.extractFromStringToIntegerByRegex(coordinateString); + + // Then + assertThat(integers).contains(10, 11); + assertThat(integers.size()).isEqualTo(2); + } +}