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

[BE] feat: 게임 생성 로직 수정 #166

Merged
merged 6 commits into from
Aug 3, 2023
Merged
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
2 changes: 1 addition & 1 deletion backend/src/main/java/com/now/naaga/game/domain/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected Game() {
}

public Game(final Player player, final Place place, final Position startPosition) {
this(null, IN_PROGRESS, player, place, startPosition, 5, new ArrayList<>(), LocalDateTime.now(), null);
this(null, IN_PROGRESS, player, place, startPosition, MAX_ATTEMPT_COUNT, new ArrayList<>(), LocalDateTime.now(), null);
}

public Game(final GameStatus gameStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@

import com.now.naaga.game.domain.Game;
import com.now.naaga.place.presentation.dto.PlaceResponse;
import com.now.naaga.player.presentation.dto.PlayerResponse;
import java.util.List;
import java.util.stream.Collectors;

public record GameResponse(Long id,
PlaceResponse place,
String gameStatus) {
String startTime,
String gameStatus,
int remainingAttempts,
CoordinateResponse startCoordinate,
PlaceResponse destination,
PlayerResponse player,
List<HintResponse> hints) {

public static GameResponse from(final Game game) {
return new GameResponse(game.getId(), PlaceResponse.from(game.getPlace()), game.getGameStatus().toString());
return new GameResponse(
game.getId(),
game.getStartTime().toString(),
game.getGameStatus().name(),
game.getRemainingAttempts(),
CoordinateResponse.of(game.getStartPosition()),
PlaceResponse.from(game.getPlace()),
PlayerResponse.from(game.getPlayer()),
HintResponse.convertToHintResponses(game.getHints())
);
}

public static List<GameResponse> convertToGameResponses(final List<Game> games) {
return games.stream()
.map(GameResponse::from)
.collect(Collectors.toList());
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.now.naaga.game.domain.Hint;
import com.now.naaga.place.presentation.dto.CoordinateResponse;
import java.util.List;

public record HintResponse(Long id,
String direction,
Expand All @@ -14,4 +15,10 @@ public static HintResponse from(final Hint hint) {
hint.getDirection().name(),
coordinateResponse);
}

public static List<HintResponse> convertToHintResponses(final List<Hint> hints) {
return hints.stream()
.map(HintResponse::from)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Place recommendRandomPlaceNearBy(final Position position) {

private Place getRandomPlace(final List<Place> places) {
final Random random = new Random();
final int randomIndex = random.nextInt();
final int randomIndex = random.nextInt(places.size());
return places.get(randomIndex);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.now.naaga.common;

import io.restassured.RestAssured;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
Expand All @@ -16,4 +18,9 @@ public abstract class CommonControllerTest {
protected void setUp() {
RestAssured.port = port;
}

protected Long getIdFromLocationHeader(ExtractableResponse<Response> extractableResponse) {
String[] split = extractableResponse.header("Location").split("/");
return Long.parseLong(split[split.length - 1]);
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package com.now.naaga.game.presentation;

import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;
import static com.now.naaga.game.domain.GameStatus.DONE;
import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
import static com.now.naaga.game.exception.GameExceptionType.ALREADY_IN_PROGRESS;
import static com.now.naaga.game.fixture.GameFixture.SEOUL_TO_JEJU_GAME;
import static com.now.naaga.game.fixture.MemberFixture.MEMBER_IRYE;
import static com.now.naaga.game.fixture.PlayerFixture.PLAYER;
import static com.now.naaga.game.fixture.PositionFixture.잠실_루터회관_정문_좌표;
import static com.now.naaga.game.fixture.PositionFixture.잠실역_교보문고_좌표;
import static com.now.naaga.member.fixture.MemberFixture.MEMBER_EMAIL;
import static com.now.naaga.member.fixture.MemberFixture.MEMBER_PASSWORD;
import static com.now.naaga.place.exception.PlaceExceptionType.CAN_NOT_FIND_PLACE;
import static com.now.naaga.place.fixture.PlaceFixture.JEJU_PLACE;
import static com.now.naaga.place.fixture.PositionFixture.SEOUL_POSITION;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
Expand All @@ -21,7 +24,14 @@
import com.now.naaga.game.domain.GameResult;
import com.now.naaga.game.domain.Hint;
import com.now.naaga.game.domain.ResultType;
import com.now.naaga.game.presentation.dto.*;
import com.now.naaga.game.presentation.dto.CoordinateRequest;
import com.now.naaga.game.presentation.dto.CreateGameRequest;
import com.now.naaga.game.presentation.dto.CreateHintRequest;
import com.now.naaga.game.presentation.dto.EndGameRequest;
import com.now.naaga.game.presentation.dto.GameResponse;
import com.now.naaga.game.presentation.dto.GameResultResponse;
import com.now.naaga.game.presentation.dto.GameStatusResponse;
import com.now.naaga.game.presentation.dto.HintResponse;
import com.now.naaga.game.repository.GameRepository;
import com.now.naaga.game.repository.GameResultRepository;
import com.now.naaga.game.repository.HintRepository;
Expand All @@ -33,12 +43,14 @@
import com.now.naaga.place.presentation.dto.PlaceResponse;
import com.now.naaga.player.domain.Player;
import com.now.naaga.player.persistence.repository.PlayerRepository;
import com.now.naaga.player.presentation.dto.PlayerResponse;
import com.now.naaga.score.domain.Score;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -77,6 +89,151 @@ protected void setUp() {
super.setUp();
}

@Test
void 게임_생성_요청시_진행중인_게임이_없으면서_주변에_추천_장소가_있다면_게임을_정상적으로_생성한다() {
// given
final Place destination = placeRepository.save(
new Place(
"잠실루터회관",
"잠실루터회관이다.",
잠실_루터회관_정문_좌표,
"잠실루터회관IMAGE",
new Player("kokodak",
new Score(1000),
new Member("[email protected]", "1031")
)));

final CreateGameRequest createGameRequest = new CreateGameRequest(
new CoordinateRequest(37.514258, 127.100883));

// when
final ExtractableResponse<Response> extract = RestAssured
.given().log().all()
.auth().preemptive().basic("[email protected]", "1031")
.contentType(ContentType.JSON)
.body(createGameRequest)
.when()
.post("/games")
.then().log().all()
.extract();

// then
final int statusCode = extract.statusCode();
final String location = extract.header("Location");
final Long gameId = getIdFromLocationHeader(extract);
final GameResponse actual = extract.as(GameResponse.class);
final GameResponse expected = new GameResponse(
gameId,
null,
IN_PROGRESS.name(),
MAX_ATTEMPT_COUNT,
com.now.naaga.game.presentation.dto.CoordinateResponse.of(잠실역_교보문고_좌표),
PlaceResponse.from(destination),
PlayerResponse.from(destination.getRegisteredPlayer()),
new ArrayList<>());

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
softAssertions.assertThat(location).isEqualTo("/games/" + gameId);
softAssertions.assertThat(actual)
.usingRecursiveComparison()
.ignoringExpectedNullFields()
.ignoringFieldsOfTypes(LocalDateTime.class)
.isEqualTo(expected);
}
);
}

@Test
void 게임_생성_요청시_진행중인_게임이_있다면_예외가_발생한다() {
// given
final Place destination = placeRepository.save(
new Place(
"잠실루터회관",
"잠실루터회관이다.",
잠실_루터회관_정문_좌표,
"잠실루터회관IMAGE",
new Player("kokodak",
new Score(1000),
new Member("[email protected]", "1031")
)));

gameRepository.save(new Game(destination.getRegisteredPlayer(), destination, 잠실역_교보문고_좌표));

final CreateGameRequest createGameRequest = new CreateGameRequest(
new CoordinateRequest(37.514258, 127.100883));

// when
final ExtractableResponse<Response> extract = RestAssured
.given().log().all()
.auth().preemptive().basic("[email protected]", "1031")
.contentType(ContentType.JSON)
.body(createGameRequest)
.when()
.post("/games")
.then().log().all()
.extract();

// then
final int statusCode = extract.statusCode();
final ExceptionResponse actual = extract.as(ExceptionResponse.class);
final ExceptionResponse expected = new ExceptionResponse(
ALREADY_IN_PROGRESS.errorCode(),
ALREADY_IN_PROGRESS.errorMessage());

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.BAD_REQUEST.value());
softAssertions.assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
}
);
}

@Test
void 게임_생성_요청시_주변에_추천_장소가_없다면_예외가_발생한다() {
// given
final Place destination = placeRepository.save(
new Place(
"잠실루터회관",
"잠실루터회관이다.",
잠실_루터회관_정문_좌표,
"잠실루터회관IMAGE",
new Player("kokodak",
new Score(1000),
new Member("[email protected]", "1031")
)));

final CreateGameRequest createGameRequest = new CreateGameRequest(
new CoordinateRequest(37.500845, 127.036953)); // 역삼역

// when
final ExtractableResponse<Response> extract = RestAssured
.given().log().all()
.auth().preemptive().basic("[email protected]", "1031")
.contentType(ContentType.JSON)
.body(createGameRequest)
.when()
.post("/games")
.then().log().all()
.extract();

// then
final int statusCode = extract.statusCode();
final ExceptionResponse actual = extract.as(ExceptionResponse.class);
final ExceptionResponse expected = new ExceptionResponse(
CAN_NOT_FIND_PLACE.errorCode(),
CAN_NOT_FIND_PLACE.errorMessage());

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.BAD_REQUEST.value());
softAssertions.assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
}
);
}

@Test
void 게임을_포기하면_게임_결과를_업데이트_한다() throws InterruptedException {
Place destination = placeRepository.save(new Place("잠실루터회관", "잠실루터회관이다.", 잠실_루터회관_정문_좌표, "잠실루터회관IMAGE", new Player("chae", new Score(1000), new Member("[email protected]", "0121"))));
Expand Down Expand Up @@ -323,9 +480,15 @@ protected void setUp() {
// then
final int statusCode = extract.statusCode();
final GameResponse actual = extract.as(GameResponse.class);

final GameResponse expected = new GameResponse(null, PlaceResponse.from(destination),
IN_PROGRESS.toString());
final GameResponse expected = new GameResponse(
game.getId(),
null,
IN_PROGRESS.name(),
MAX_ATTEMPT_COUNT,
com.now.naaga.game.presentation.dto.CoordinateResponse.of(잠실역_교보문고_좌표),
PlaceResponse.from(destination),
PlayerResponse.from(destination.getRegisteredPlayer()),
new ArrayList<>());

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
Expand Down